簡體   English   中英

函數vs struct的類型參數(生命期問題)

[英]type parameter for function vs struct (lifetime issue)

考慮以下測試用例:

#![allow(unstable)]
trait Choose<'o> { 
    fn choose(a: &'o u64, b: &'o u32) -> Self; 
}

impl<'o> Choose<'o> for &'o u64 { 
    fn choose(a: &'o u64, _b: &'o u32) -> &'o u64 { a }
}

impl<'o> Choose<'o> for &'o u32 { 
    fn choose(_a: &'o u64, b: &'o u32) -> &'o u32 { b }
} // '

struct Handler {
    a: u64,
    b: u32,
}

impl Handler {
    fn new() -> Handler {
        Handler { a: 14, b: 15 }
    }

    fn find<'a, V, W>(&'a mut self, value: W) -> Option<V> where V: Choose<'a>, W: PartialEq<V> { // '
        let v = Choose::choose(&self.a, &self.b);
        if value == v {
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    let mut h = Handler::new();

    {
        let v_a = h.find::<&u64, &u64>(&14u64);
        println!("v_a = {:?}", v_a);
    }

    {
        let v_b = h.find::<&u64, &u64>(&15u64);
        println!("v_b = {:?}", v_b);
    }
}

圍欄

假設我在Handler :: find中有一些改變狀態,所以我需要&mut self 但是指向Handler內部的v_av_b變量都存在於自己的塊中,因此這里沒有借用問題。 在這種情況下,直接為find方法指定類型參數V ,並且所有內容都按預期編譯。

不過,接我一招參數V輸入處理程序類型簽名,並停止與編譯“不能借h為可變不止一次同時更”錯誤:

#![allow(unstable)]
trait Choose<'o> { 
    fn choose(a: &'o u64, b: &'o u32) -> Self; 
}

impl<'o> Choose<'o> for &'o u64 { 
    fn choose(a: &'o u64, _b: &'o u32) -> &'o u64 { a }
}

impl<'o> Choose<'o> for &'o u32 { 
    fn choose(_a: &'o u64, b: &'o u32) -> &'o u32 { b }
} // '

struct Handler<V> {
    a: u64,
    b: u32,
}

impl<V> Handler<V> {
    fn new() -> Handler<V> {
        Handler { a: 14, b: 15 }
    }

    fn find<'a, W>(&'a mut self, value: W) -> Option<V> where V: Choose<'a>, W: PartialEq<V> { // '
        let v = Choose::choose(&self.a, &self.b);
        if value == v {
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    let mut h = Handler::<&u64>::new();

    {
        let v_a = h.find(&14u64);
        println!("v_a = {:?}", v_a);
    }

    {
        let v_b = h.find(&15u64);
        println!("v_b = {:?}", v_b);
    }
}

圍欄

我真的無法理解其中的區別。 變量v_a死后,為什么不發布可變借用?

我認為這里發生的事情是:在你的main ,當你做let mut h = Handler::<&u64>::new(); ,你的處理程序現在與u64引用u64 因此,即使v_a在下一個塊中死亡,V的生命周期必須是h的生命周期,它仍然存在。

順便說一句,問題不在於你已編寫的代碼,而是代碼中你或其他人仍然可以編寫。 鑒於您使用不受約束的V定義Handler,我可以繼續執行:

// in the meanwhile, in another crate...
// I create another trait
trait MyTrait {
    fn foo(&self) -> &u64;
}

// and implement it for Handler<&u64>
impl<'a> MyTrait for Handler<&'a u64> {
    fn foo(&self) -> &u64 { &self.a }
}

然后這是合法的:

let h = Handler::<&u64>::new();    
println!("{}", h.foo()); // prints 14

所以,每當我做let h = Handler::<&u64>::new(); 和你一樣,唯一安全的選擇是讓&64至少和h一樣長。

如果你可以使用u64作為V ,而不是&u64你會沒事的。 像這樣的東西會很少改變你的程序(注意我仍在使用引用,而不是通過值傳遞),但允許你為u32 / 64而不是&u32 / 64參數化Handler:

trait Choose<'o> { 
    fn choose(a: &'o u64, b: &'o u32) -> &'o Self; 
}

impl<'o> Choose<'o> for u64 { 
    fn choose(a: &'o u64, _b: &'o u32) -> &'o u64 { a }
}

impl<'o> Choose<'o> for u32 { 
    fn choose(_a: &'o u64, b: &'o u32) -> &'o u32 { b }
}

struct Handler<V> {
    a: u64,
    b: u32,
}

impl<V> Handler<V> {
    fn new() -> Handler<V> {
        Handler { a: 14, b: 15 }
    }

    fn find<'a, W>(&'a mut self, value: W) -> Option<&'a V> where V: Choose<'a>, W: PartialEq<&'a V> {
        let v = Choose::choose(&self.a, &self.b);
        if value == v {
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    let mut h = Handler::<u64>::new();

    {
        let v_a = h.find(&14u64);
        println!("v_a = {:?}", v_a);
    }

    {
        let v_b = h.find(&15u64);
        println!("v_b = {:?}", v_b);
    }
}

圍欄

這是我對問題的理解,其他人可能能夠提供更具體的解釋。

通過將類型參數添加到結構中,您可以將該類型存儲在結構中 既然你還指定你的類型具有特征Choose<'a> 並且 'aself的生命周期相關聯,那么當你創建函數時,Rust必須假設你可能會在結構中存儲一個(可變的)引用呼叫。 然后編譯器必須將您的可變借位轉移到該函數,並且它不知道它何時結束。 唯一安全的時間是對象本身超出范圍

這是存儲V的示例:

fn find<'a, W>(&'a mut self, value: W) -> Option<V> where V: Choose<'a>, W: PartialEq<V> { //'
    let v = Choose::choose(&self.a, &self.b);

    self.c = Some(Choose::choose(&self.a, &self.b)); // saved

    if value == v {
        Some(v)
    } else {
        None
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM