The Unfun Cat
The Unfun Cat

Reputation: 31898

No method named X found for type *mut Y in the current scope

I want to call the method a on a struct I. I am told Rust can't find the method, but am unsure why:

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

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

This is a minimal reproducible example:

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

How do I fix this?

Upvotes: 1

Views: 7097

Answers (3)

oli_obk
oli_obk

Reputation: 31163

The method a technically takes a self: &I argument (but the shorthand &self is more convenient). So the method expects a reference to an I. The variable i is of type *mut I, but a &I is expected. These types obviously do not match up. But you can either easily convert your i to a &I by dereferencing the raw pointer and immediately referencing it again ((&*i).a(42)). Alternatively you can implement the method for pointers:

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

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

Upvotes: 2

Matthieu M.
Matthieu M.

Reputation: 299730

Let's remove the extern C stuff, it is not useful here:

#[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 issue is that pointers in Rust are extremely limited: they only have the methods implemented on the primitive pointer type.

Basically, you can check if a pointer is null, compare it for equality, perform some arithmetic and dereference it. Note that few operations are actually unsafe on a pointer (mostly arithmetic and dereference).

To actually use the pointee, you first need to dereference the pointer to obtain a reference from it; this is unsafe, but using the reference is then safe.

Thus you can rewrite i_a as either:

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

or:

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

and then it will work.

Upvotes: 4

Shepmaster
Shepmaster

Reputation: 430368

I want to call the method a on a struct I

The code does not have a struct I; it has a mutable pointer to a struct I.

I'd strongly recommend reading the chapter on raw pointers before doing any in-depth work with them. Rust is a great language and the compiler works very hard to prevent screw ups when you use the safe aspects; when you get into unsafe you need to know what you are doing because you have told the compiler to stand back and watch.

One specific difference between references and raw pointers is that raw pointers may be NULL. References, on the other hand, may never be NULL. That's one reason why it is required to use an unsafe block any time you dereference a raw pointer.

Normally, you check for a NULL pointer and then convert it to a reference if it's not NULL:

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

Now that you have a reference, you can call methods.

There are also helper functions like 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,
    }
}

The code also has a giant hole waiting to be exploited. i_a purports to return a pointer to an integer, but the code returns an integer directly. That's a very bad mismatch

Upvotes: 3

Related Questions