2016-11-08 49 views
0

我想在struct I上調用方法a。我告訴鏽找不到方法,但我不確定爲什麼:在當前範圍內沒有找到類型爲* mut Y的名爲X的方法

error: no method named `a` found for type `*mut I` in the current scope 

--> src/lib.rs:7:16 
    | 
7 |  unsafe { i.a(5) } 
    |    ^

這是一個最小的可重複的例子:

extern crate libc; 
use self::libc::int32_t; 

#[no_mangle] 
pub extern "C" fn i_a(i: *mut I) -> *mut int32_t { 
    unsafe { i.a(5) } // error: no method named `a` found for type `*mut I` in the current scope 
} 

#[derive(Debug, PartialEq)] 
pub struct I { 
    pub values: Vec<i32>, 
} 

impl I { 
    pub fn a(&self, n: i32) -> i32 { 
     return 0; 
    } 
} 

我該如何解決這個問題?

+2

取消引用指針與引用不同,不是隱式的。您必須取消引用該指針。 –

+0

side-note:即使你解決了你的問題,你的'i_a'函數返回'* mut int32_t',而'a'方法返回'i32',類型將不匹配。 –

回答

3

讓我們去掉外部C的東西,它是沒有用在這裏:

#[derive(Debug, PartialEq)] 
pub struct I { 
    pub values: Vec<i32>, 
} 

impl I { 
    pub fn a(&self, n: i32) -> i32 { 
     return 0; 
    } 
} 

pub fn i_a(i: *mut I) -> i32 { 
    unsafe { i.a(5) } 
} 

的問題是,在鏽指針非常有限的:它們只對the primitive pointer type實現的方法。

基本上,你可以檢查指針是否爲空,比較它是否相等,執行一些算術運算並對其進行解引用。請注意,很少有操作對指針實際上是不安全的(主要是算術和解引用)。

要實際使用pointee,首先需要取消引用指針以從中獲取引用;這是不安全的,但使用參考是安全的。

因此你可以重寫i_a爲兩種:

pub fn i_a(i: *mut I) -> i32 { 
    unsafe { (*i).a(5) } 
} 

或:

pub fn i_a(i: *mut I) -> i32 { 
    unsafe { &*i }.a(5) 
} 

,然後它會工作。

+0

我希望人們盲目複製粘貼你的代碼,所以我建議添加'NULL'檢查。 – Shepmaster

+0

@Shepmaster:那麼,如果指針爲空,那麼它可能會崩潰;這是你無論如何都會傳遞任何野指針的行爲。 –

+1

該反應似乎反常*放任自流*。遵循邏輯到荒謬的結局,看起來像Rust所做的許多(所有)檢查都是無關緊要的,因爲如果你這樣做的話「錯誤」,它可能會崩潰。 – Shepmaster

3

我要調用的方法a在結構I

代碼中並沒有一個struct我;它有一個可變指針到結構I

我會強烈建議在與他們進行任何深入的工作之前閱讀chapter on raw pointers。 Rust是一門很棒的語言,當你使用安全的方面時,編譯器會非常努力地防止搞砸;當你遇到不安全的問題時需要知道你在做什麼,因爲你已經告訴編譯器退後一步觀察。

引用和原始指針之間的一個特定差異是原始指針可能是NULL。另一方面,參考文獻決不是NULL。這就是爲什麼在您解引用原始指針時需要使用unsafe塊的原因之一。

通常情況下,你check for a NULL pointer,然後將其轉換爲參考,如果它不是NULL

let i = &*i;  // For `&T` 
let i = &mut *i; // For `&mut T` 

現在你有一個參考,你可以調用的方法。

也有輔助功能,如as_ref

pub extern "C" fn i_a(i: *mut I) -> int32_t { 
    match unsafe { i.as_ref() } { 
     Some(i) => i.a(5), 
     None => 42, 
    } 
} 

的代碼也有一個巨洞等着被利用。 i_a聲稱返回一個指針爲一個整數,但代碼直接返回一個整數。這是一個非常糟糕的錯配

2

方法a從技術上講需要一個self: &I參數(但簡寫&self更方便)。因此該方法預計會參考I。變量i的類型爲*mut I,但預計有&I。這些類型顯然不匹配。但是,您可以通過解引用原始指針並立即再次引用它((&*i).a(42))來輕鬆地將i轉換爲&I。或者,您可以實現指針的方法:

trait A { 
    fn a(self, n: i32) -> i32; 
} 

impl A for *mut I { 
    fn a(self, n: i32) -> i32 { 
     return 0; 
    } 
} 
相關問題