ฉันมีstructที่อ้างอิงค่า (เพราะ?Sizedหรือใหญ่มาก) ค่านี้ต้องอยู่กับโครงสร้างแน่นอน
อย่างไรก็ตาม โครงสร้างไม่ควรจำกัดผู้ใช้ในการทำให้สำเร็จ ไม่ว่าผู้ใช้จะแรปค่าใน a BoxหรือRcหรือทำให้'staticค่านั้น ค่าก็ต้องคงอยู่ด้วยโครงสร้าง การใช้ lifes ที่ระบุชื่อจะซับซ้อนเนื่องจากการอ้างอิงจะถูกย้ายไปรอบๆ และอาจมีอายุยืนกว่าของstructเรา สิ่งที่ฉันกำลังมองหาคือประเภทตัวชี้ทั่วไป (ถ้ามี / สามารถมีอยู่ได้)

struct จะแน่ใจได้อย่างไรว่าค่าอ้างอิงจะคงอยู่ตราบเท่าที่ struct นั้นคงอยู่ โดยไม่ระบุวิธี?

ตัวอย่าง ( is.gd/Is9Av6 ):

type CallBack = Fn(f32) -> f32;

struct Caller {
    call_back: Box<CallBack>,
}

impl Caller {
    fn new(call_back: Box<CallBack>) -> Caller {
        Caller {call_back: call_back}
    }

    fn call(&self, x: f32) -> f32 {
        (self.call_back)(x)
    }
}

let caller = {
    // func goes out of scope
    let func = |x| 2.0 * x; 
    Caller {call_back: Box::new(func)}
};

// func survives because it is referenced through a `Box` in `caller`
let y = caller.call(1.0);
assert_eq!(y, 2.0);

เรียบเรียง ดีไปหมด แต่ถ้าเราไม่ต้องการใช้ a Boxเป็นตัวชี้ไปยังฟังก์ชันของเรา (สามารถเรียกBoxตัวชี้ได้ใช่ไหม) แต่อย่างอื่น เช่นRcสิ่งนี้จะไม่เกิดขึ้น เนื่องจากCallerจำกัดตัวชี้ให้เป็นBox.

let caller = {
    // function is used by `Caller` and `main()` => shared resource
    // solution: `Rc`
    let func = Rc::new(|x| 2.0 * x); 
    let caller = Caller {call_back: func.clone()}; // ERROR Rc != Box

    // we also want to use func now
    let y = func(3.0);

    caller
};

// func survives because it is referenced through a `Box` in `caller`
let y = caller.call(1.0);
assert_eq!(y, 2.0);

( is.gd/qUkAvZ )

วิธีแก้ปัญหาที่เป็นไปได้: Deref? ( http://is.gd/mmY6QC )

use std::rc::Rc;
use std::ops::Deref;

type CallBack = Fn(f32) -> f32;

struct Caller<T>
        where T: Deref<Target = Box<CallBack>> {
    call_back: T,
}

impl<T> Caller<T> 
        where T: Deref<Target = Box<CallBack>> {
    fn new(call_back: T) -> Caller<T> {
        Caller {call_back: call_back}
    }

    fn call(&self, x: f32) -> f32 {
        (*self.call_back)(x)
    }
}

fn main() {
    let caller = {
        // function is used by `Caller` and `main()` => shared resource
        // solution: `Rc`
        let func_obj = Box::new(|x: f32| 2.0 * x) as Box<CallBack>;
        let func = Rc::new(func_obj); 
        let caller = Caller::new(func.clone());

        // we also want to use func now
        let y = func(3.0);

        caller
    };

    // func survives because it is referenced through a `Box` in `caller`
    let y = caller.call(1.0);
    assert_eq!(y, 2.0);
}

นี้เป็นวิธีที่จะไปกับ Rust? ใช้Deref? มันใช้งานได้อย่างน้อย

ฉันพลาดบางสิ่งที่ชัดเจนหรือไม่?

คำถามนี้ไม่สามารถแก้ปัญหาของฉันได้ เนื่องจากค่านี้แทบจะใช้งานไม่ได้ในรูปแบบT.

ตอบ

ในขณะที่Derefมีฟังก์ชันที่จำเป็นAsRefและBorrowเหมาะสมกว่าสำหรับสถานการณ์นี้ ( Borrowมากกว่าAsRefในกรณีของ struct) คุณลักษณะทั้งสองนี้ทำให้ผู้ใช้ของคุณสามารถใช้Box<T>และRc<T>และArc<T>ยังBorrowช่วยให้ผู้ใช้ใช้&Tและ Tโครงสร้าง ของคุณCallerสามารถเขียนได้ดังนี้:

use std::borrow::Borrow;

struct Caller<CB: Borrow<Callback>> {
    callback: CB,
}

จากนั้น เมื่อคุณต้องการใช้callbackฟิลด์ คุณต้องเรียกใช้ เมธอด borrow()(หรือas_ref()) ดังนี้

impl<CB> Caller<CB> 
    where CB: Borrow<Callback>
{
    fn new(callback: CB) -> Caller<CB> {
        Caller { callback: callback }
    }

    fn call(&self, x: f32) -> f32 {
        (self.callback.borrow())(x)
    }
}

มันขัดข้องด้วยคอมไพเลอร์ที่เสถียรในปัจจุบัน (1.1) แต่ไม่ใช่กับเบต้าหรือทุกคืน (เพียงใช้ลิงก์ Playpen ล่าสุดของคุณและเปลี่ยนการตั้งค่า "ช่อง" ที่ด้านบน) ฉันเชื่อว่าการสนับสนุนRc<Trait>เป็นเพียงบางส่วนใน 1.1; มีการเปลี่ยนแปลงบางอย่างที่ไม่ทันเวลา นี่อาจเป็นสาเหตุที่รหัสของคุณใช้งานไม่ได้

เพื่อตอบคำถามในการใช้Derefสิ่งนี้... หากการ dereference ตัวชี้เป็นสิ่งที่คุณต้องการ... แน่นอน เป็นเพียงคำถามว่าคุณลักษณะที่คุณเลือกสนับสนุนการดำเนินการที่คุณต้องการหรือไม่ ถ้าใช่เยี่ยมมาก

ในทางกลับกัน คุณสามารถเขียนคุณลักษณะใหม่ที่แสดงถึง ความหมาย ที่คุณต้องการ และนำไปใช้กับประเภทที่มีอยู่ได้เสมอ จากที่คุณพูดมา ในกรณีนี้ไม่จำเป็น