Dave Mason
Dave Mason

Reputation: 901

How do I resolve 'expected struct, found reference` for borrowed value?

I get an error referencing a boxed value:

error[E0308]: mismatched types
   --> src/interpreter.rs:284:37
    |
284 |             table[index].function = method;
    |                                     ^^^^^^ expected struct `Box`, found `&Box<MethodType>`
    |
    = note: expected struct `Box<MethodType>`
            found reference `&Box<MethodType>`

If I dereference it by saying *method I get an error because MethodType doesn't implement Copy (which would be a pain, because it includes a couple of Vecs and it would be very expensive to copy). Maybe I could fix it with ManuallyDrop, but that doesn't seem very idiomatic, and I spent some time this afternoon getting rid of a ManuallyDrop.

Perhaps I shouldn't be passing it by reference (the only two calls to addMethodToTable are in the following method, addMethodToDispatch but they are in loops, because I need to try allocation several times). Maybe it should be an Rc instead. This is part of a lot of code, so I hope this snippit is enough to show what I'm doing wrong:

#[derive(Clone)]
enum MethodType {
    Function(Function),
    Method(Method),
    NoType,
}
#[derive(Clone)]
struct MethodMatch {
    selector: usize,
    function: Box<MethodType>,
}
pub struct Dispatch {
    class: Object,
    table: Box<[MethodMatch]>,
}
fn addMethodToTable(table:&mut Vec<MethodMatch>,selector:usize,method:&Box<MethodType>) -> bool {
    let len = table.capacity();
    let hash = selector%(len-DISPATCH_OVERFLOW);
    for index in hash..hash+DISPATCH_OVERFLOW {
        if let SelectorMatch::Other = table[index].selector_match(selector) {
            // slot taken
        } else {
            table[index].selector = selector;
            table[index].function = method;
            return true
        }
    }
    false
}
fn addMethodToDispatch(class:ClassIndex,selector:Object,method:Box<MethodType>) {
    let selector = selector.raw()>>3;
    while ... {
                    table = Vec::with_capacity(count+DISPATCH_OVERFLOW);
                    addMethodToTable(&mut table,selector,&method);
                    for mm in disp.table.iter() {
                        if addMethodToTable(&mut table,mm.selector,&mm.function) {unfinished = true;break}
                    }
                }
                table.resize(table.capacity(),Default::default());
                disp.table=table.into_boxed_slice()
            },
            index => {
                disp.table[index].selector = selector;
                disp.table[index].function = method
            },

I was having such a productive day until I hit this... thinking I was finally "getting" Rust!

Upvotes: 1

Views: 4195

Answers (1)

Svetlin Zarev
Svetlin Zarev

Reputation: 15723

Your struct expects an owned type - function must be a Box:

#[derive(Clone)]
struct MethodMatch {
    selector: usize,
    function: Box<MethodType>,
}

but in your other method the parameter method is a reference to a Box which are two very different types:

`fn addMethodToTable(....,method: &Box<MethodType>)

There are two ways to fix the issue (not all may be applicable in your case):

  1. Change the reference to an owned type: method: &Box<MethodType> should become method: Box<MethodType>

  2. Because your MethodType implements Clone, just clone it in order to get an owned type from the reference: table[index].function = method.clone();

  3. If you are free to change the struct definition, you can use Rc<T> instead of Box<T>. Thus you can use Rc::clone(reference) and clone only the pointer instead of the whole struct.

Upvotes: 2

Related Questions