Rust結構體中包含自身成員的引用時,生命週期應當如何標註?

時間 2021-05-05 18:24:55

1樓:hjiayz

加上refcell就行了,如果多執行緒需要上鎖Rust Playground

usestd::cell::RefCell;pub

struct

CallBack

<'a,

T,F>

pubstruct

Context

<'a,

T,F>

impl

<'a,

T: Copy

+Default

,F: Fn(T

)>CallBack

<'a,

T,F>

}impl

<'a,

T: Copy

+Default

,F: Fn(T

)>Context

<'a,

T,F>

}pub

fnget_value(&

self

)-> T

pubfn

set_value(&

'aself

,new_value: T)}

pubfn

add_callback(&

'aself

,callback: F))

}}#[cfg(test)]

modtests",

value

));context

.set_value(5

);assert_eq!(

5,context

.get_value

());}}

2樓:傳統的幻想書屋

你最好換個設計,互相引用是能避免就盡量避免的,就算你的context要擁有callback,但是可以讓callback不引用context,而是給notify加個引數,把context引用傳進去,這樣至少不會要callback物件本身持有context引用。否則互相擁引用對方會導致你兩個引用都是不可變的之後,無法可變借用其中任何乙個,那你的add和set就做不了了。

然後就是,你這個設計本身就很有問題,首先你的引數是乙個Fn(T)->()型別,這實際上代表乙個可呼叫物件,或者有捕獲的閉包,而不僅僅是乙個函式指標,你這樣寫,傳的閉包沒有捕獲變數還好,編譯器會自動看作函式指標,但是一旦要捕獲變數就不行了,因為閉包不是固定大小的。

然後,既然取消了相互引用,那麼這個生命週期也是不必要寫的了,幫你整體改了一下。

pubstruct

CallBack

pubstruct

Context

impl

+Default

>CallBack

pubfn

new(

f: Box

)-> ()

>)-> Self}}

impl

+Default

>Context

}pub

fnget_value(&

self

)-> T

pubfn

set_value(&

mutself

,new_value: T)}

pubfn

add_callback(&

mutself

,callback: Box

)-> ()

>)}fnadd_callback()"

,value

)));

context

.add_callback

(Box::new(|

value

|println!(

"second callback:value changed to {}"

,value

)));

context

.add_callback

(Box::new(|

value

|println!(

"third callback:value changed to {}"

,value

)));

context

.set_value(5

);assert_eq!(

5,context

.get_value

());}fn

main

()這是執行結果

first callback:value changed to 5

second callback:value changed to 5

third callback:value changed to 5

然後就是用函式指標,感覺更符合你的需求

pub struct StaticCallBack

pub struct StaticContext

impl StaticCallBack ", value));

context.add_callback(|value| println!("second callback:value changed to {}", value));

context.add_callback(|valueprintln!("third callback:

value changed to {}", value不能捕獲變數context.add_callback(other_func);

context.set_value(5);

assert_eq!(5, context.get_value());

}fn main()

執行結果跟上面一樣,就不放了。

所以是你自己搞複雜了,要實現這個功能沒那麼複雜。。。。。。

更新,如果Context只是持有閉包的引用而不是所有權,那麼應該用&dyn Fn(T)->()型別,並指明生命週期引數。

pubstruct

CallBack

<'a,

T>pubstruct

Context

<'a,

T>impl

<'a,

T: Copy

+Default

>CallBack

<'a,

T>pubfn

new(

f: &

'adynFn(

T)->())

-> Self}}

impl

<'a,

T: Copy

+Default

>Context

<'a,

T>}pub

fnget_value(&

self

)-> T

pubfn

set_value(&

mutself

,new_value: T)}

pubfn

add_callback(&

mutself

,callback: &

'adynFn(

T))}fn

add_callback

(num: i32)"

,value

);println!(

"capture outer value:{}"

,num

);//捕獲num

};let

call_back2

=|value|"

,value

);println!(

"capture outer value:{}"

,num

);};

letcall_back3

=|value|"

,value

);println!(

"capture outer value:{}"

,num

);};

//需要繫結乙個名稱,保證閉包比context活得長。

letmut

context

=Context::new

();context

.add_callback(&

call_back1

);//傳引用(可變引用也是可以的)

context

.add_callback(&

call_back2

);context

.add_callback(&

call_back3

);context

.set_value(5

);assert_eq!(

5,context

.get_value

());}fn

main

()用引用的話應該是不需要分配堆記憶體的,因為用引用保證了閉包比你的context活得長,就直接存個胖指標指向棧上的閉包就行了,不需要存在堆裡,但是你如果你的context要持有閉包,那引數如果是引用就只能clone乙個了。

最後是閉包的可變引用,也就是傳進來的是FnMut,那你就把裡面都改成可變就行了。

pubstruct

CallBack

<'a,

T>pubstruct

Context

<'a,

T>impl

<'a,

T: Copy

+Default

>CallBack

<'a,

T>pubfn

new(

f: &

'amut

dynFnMut(T

)->())

-> Self}}

impl

<'a,

T: Copy

+Default

>Context

<'a,

T>}pub

fnget_value(&

self

)-> T

pubfn

set_value(&

mutself

,new_value: T)}

pubfn

add_callback(&

mutself

,callback: &

'amut

dynFnMut(T

))}fnadd_callback

(num1:&

muti32

,num2:&

muti32

,num3:&

muti32)"

,value);*

num1+=1

;println!(

"capture outer value:{}"

,num1

);};

letmut

call_back2

=|value|"

,value);*

num2+=1

;println!(

"capture outer value:{}"

,num2

);};

letmut

call_back3

=|value|"

,value);*

num3+=1

;println!(

"capture outer value:{}"

,num3

);};

letmut

context

=Context::new

();context

.add_callback(&

mutcall_back1

);context

.add_callback(&

mutcall_back2

);context

.add_callback(&

mutcall_back3

);context

.set_value(5

);assert_eq!(

5,context

.get_value

());}fn

main

()測試結果

first callback:value changed to 5

capture outer value:51

second callback:value changed to 5

capture outer value:101

third callback:value changed to 5

capture outer value:151

反正意思就是這麼個意思,設計方案也挺多的,要改建議先改設計方案,而不是先去搞一些跟rust所有權系統作對的設計。

在 C 17 中包含陣列的聚合型別如何獲取成員個數

判斷struct unbinding,用這個方法本來就不行。換gcc clang的 擴充套件,把unbinding的stmt轉為expr,在判斷expr合法性即可。 不是很明白,序列化和反序列化的意思,如果你是要計算成員數量的話 包括陣列內 include include include inclu...

力量舉中的體重級別包含體脂很高的人嗎?

Noir 比如某人70kg體重,體脂很高,那麼他的三大項成績也要以70的多少倍為標準嗎?是的,沒人管你體脂多少,上比賽規定的稱,稱完多重就是多重 2.問題是脂肪不產生力量,他和低體脂的70kg比起來是不是很大劣勢? 卞策 包含。確實存在劣勢。按你這麼說,確實高體脂的乙在這個體重的肌肉表現更好,因為他...

在 C 11 中,如何為匿名的結構體新增建構函式?

暮無井見鈴 include intmain foo std cout foo n p this endl return0 可以用捕獲 this 的藍陀表示式再帶上 替換最後乙個非靜態成員的預設初始化器。但其他特殊成員函式似乎沒法手動定製 胖財 顯然沒有名字的類是沒法顯式寫構造的,但是我們有C 11的...