在当前范围内没有为类型* mut Y找到名为X的方法

时间:2016-11-08 14:38:41

标签: rust

我想在结构a上调用方法I。我被告知Rust无法找到方法,但我不确定原因:

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;
    }
}

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:3)

  

我想在结构a

上调用方法I

代码有结构I;它有可变指针到结构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声称将指针返回到整数,但代码直接返回一个整数。这是一个非常糟糕的不匹配

答案 1 :(得分:3)

让我们删除extern 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) }
}

问题是Rust中的指针非常有限:它们只在the primitive pointer type上实现了方法。

基本上,您可以检查指针是否为空,比较它是否相等,执行一些算术并取消引用它。请注意,很少有操作对指针实际上是不安全的(主要是算术和解除引用)。

要实际使用指针,首先需要取消引用指针以从中获取引用;这是不安全的,但使用引用是安全的。

因此,您可以将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)
}

然后它会起作用。

答案 2 :(得分:2)

方法a在技术上采用self: &I参数(但速记&self更方便)。因此,该方法需要引用I。变量i的类型为*mut I,但预计会&I。这些类型显然不匹配。但您可以通过取消引用原始指针并立即再次引用它(i)轻松地将&I转换为(&*i).a(42)。或者,您可以实现指针的方法:

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

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