[英]How do I get a function pointer from a trait in Rust?
我該如何克服這樣的問題:
struct Test {
foo: Option<fn()>
}
impl Test {
fn new(&mut self) {
self.foo = Option::Some(self.a);
}
fn a(&self) { /* can use Test */ }
}
我收到此錯誤:
error: attempted to take value of method `a` on type `&mut Test`
--> src/main.rs:7:36
|
7 | self.foo = Option::Some(self.a);
| ^
|
= help: maybe a `()` to call it is missing? If not, try an anonymous function
如何從特征傳遞函數指針? 類似於在這種情況下會發生的情況:
impl Test {
fn new(&mut self) {
self.foo = Option::Some(a);
}
}
fn a() { /* can't use Test */ }
什么你想要做的,是從(這里使用Python術語,因為銹沒有一個詞來形容)綁定的方法獲得一個函數指針。 你不能
首先,因為Rust沒有“綁定”方法的概念; 也就是說,你不能引用與調用者(在其左邊的事情的方法.
)已經到位的約束。 如果您想構造一個與此近似的可調用對象,則可以使用閉包; 即 || self.a()
|| self.a()
。
但是,由於閉包不是函數指針 ,因此這仍然行不通。 像某些其他語言一樣,沒有可調用事物的“基本類型”。 函數指針是一種特定的可調用類型。 閉包是完全不同的。 相反,有些特征(在實現時)使類型可調用。 它們是Fn
, FnMut
和FnOnce
。 因為它們是特征,所以不能將它們用作類型,而必須從間接層的后面使用它們,例如Box<FnOnce()>
或&mut FnMut(i32) -> String
。
現在,您可以更改Test
來存儲Option<Box<Fn()>>
,但這仍然無濟於事。 那是由於另一個其他問題:您試圖在內部存儲對結構的引用。 這不能很好地工作。 如果設法做到這一點,則可以有效地使“ Test
值永久不可用。 更可能的是編譯器不會讓您走得那么遠。
除了 :您可以做到這一點,但不能不依靠引用計數和動態借閱檢查,這不在本文范圍之內。
因此,您所提出的問題的答案是:您沒有。
讓我們改變一下問題:我們可以嘗試存儲一個完全不嘗試捕獲調用者的可調用對象,而不是嘗試使用自我引用閉包。
struct Test {
foo: Option<Box<Fn(&Test)>>,
}
impl Test {
fn new() -> Test {
Test {
foo: Option::Some(Box::new(Self::a)),
}
}
fn a(&self) { /* can use Test */ }
fn invoke(&self) {
if let Some(f) = self.foo.as_ref() {
f(self);
}
}
}
fn main() {
let t = Test::new();
t.invoke();
}
現在,可存儲的可調用對象是一個函數,該函數顯式地采用調用方,並通過循環引用來回避問題。 通過將其稱為自由函數,我們可以使用它直接存儲Test::a
。 還要注意,因為Test
是實現類型,所以我也可以將其稱為Self
。
另外 :我還糾正了您的
Test::new
函數。 Rust沒有構造函數,只有能返回值的函數。
如果您有信心永遠不要在foo
存儲閉包,則可以將Box<Fn(&Test)>
替換為fn(&Test)
。 這限制了您使用函數指針,但是避免了額外的分配。
如果您還沒有的話,我強烈建議您閱讀Rust Book 。
您的代碼幾乎沒有錯誤。 新函數(按照慣例)不應采用自我引用,因為它應該創建自我類型。
但是真正的問題是, Test::foo
期望函數類型為fn()
,但是如果將foo
的類型更改為fn(&Test)
fn()
,則Test::a
的類型為fn(&Test)
== fn a(&self)
fn(&Test)
它會工作。 另外,您需要使用帶有特征名稱的函數名稱,而不是self
。 而不是分配給self.a
您應該分配Test::a
。
這是工作版本:
extern crate chrono;
struct Test {
foo: Option<fn(&Test)>
}
impl Test {
fn new() -> Test {
Test {
foo: Some(Test::a)
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
test.foo.unwrap()(&test);
}
另外,如果您要在new()
函數中分配一個字段,並且必須始終設置該值,則無需使用Option
而是可以這樣:
extern crate chrono;
struct Test {
foo: fn(&Test)
}
impl Test {
fn new() -> Test {
Test {
foo: Test::a
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
(test.foo)(&test); // Make sure the paranthesis are there
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.