Rust Double Reference Value

2.1k Views Asked by At

Looking through the blurz bluetooth library for Rust.

There is a variable declared with a value equal to a reference of a temp value(?).

This value is then passed into another function by reference.

How is ownership handled for a variable set to the value of a reference in a single statement and what does it mean to then use that reference as a reference?

Example:

let bt_session = &Session::create_session(None)?;
let adapter: Adapter = Adapter::init(bt_session)?;
adapter.set_powered(true)?;

let session = DiscoverySession::create_session(
    &bt_session,
    adapter.get_id()
)?;

See variable bt_session.

Source code example link.

1

There are 1 best solutions below

3
On BEST ANSWER

A commented example to illustrate some concepts:

use rand;

#[derive(Debug)]
struct Struct {
    id: i32
}

impl Drop for Struct {
    fn drop(&mut self) {
        // print when struct is dropped
        println!("dropped {:?}", self);
    }
}

fn rand_struct() -> Struct {
    Struct { id: rand::random() }
}

/*
this does not compile:

fn rand_struct_ref<'a>() -> &'a Struct {
    &rand_struct()
    // struct dropped here so we can't return it to caller's scope
}
*/

fn takes_struct_ref(s: &Struct) {}

fn main() {
    // brings struct into scope and immediately creates ref to it
    // this is okay because the struct is not dropped until end of this scope
    let s = &rand_struct();
    
    println!("holding ref to {:?}", s);
    
    // all these work because of deref coercion
    takes_struct_ref(s);
    takes_struct_ref(&s);
    takes_struct_ref(&&s);
    
    // struct dropped here
}

playground

To answer your first question: You can't return a reference from a function if the underlying value is dropped at the end of the function but it's okay to immediately make a reference to a returned value since that value lives for the rest of the caller's scope. You can see this in action if you run the above example, as holding ref to Struct { id: <id> } will get printed before dropped Struct { id: <id> }.

To answer your second question: the reason you can pass an &Struct or an &&Struct or an &&&Struct and so on to function which only takes an &Struct is because of a Rust syntax sugar feature called deref coercion which automatically derefs variables when they are used as function arguments or as part of method calls. In your shared code examples it looks like a ref of a ref is being passed to the function but actually it's just passing a single ref after auto deref coercion takes place.

See also