1

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.

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
webish
  • 701
  • 2
  • 9
  • 17
  • Can you clarify your questions? "How does x work?" is kinda ambiguous. Can you explain what you find wrong or confusing about the shared code example? – pretzelhammer Nov 26 '20 at 16:26
  • tried to update the question but really, the syntax is unclear to me what the borrowing implications are and reference tree. – webish Nov 26 '20 at 16:39
  • 1
    Does this answer your question? [Why is it legal to borrow a temporary?](https://stackoverflow.com/questions/47662253/why-is-it-legal-to-borrow-a-temporary) – kmdreko Nov 26 '20 at 16:57

1 Answers1

4

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

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
  • so is the entire purpose of the &s argument for clarity? is there ever a reason to use && or &&&? – webish Nov 26 '20 at 17:06
  • You would have to use && or &&& if the function (for whatever reason) specifically expected an && or &&&. Also, I wouldn't say you should write &s when the function expects a ref if s is already a ref. I don't know why test6 does that but my best guess is the author was refactoring some code and forgot to drop the unnecessary & in front of the variable. – pretzelhammer Nov 26 '20 at 17:12
  • thank you for the well thought out response plus example and sharing some intuition, this makes a lot more sense now. – webish Nov 26 '20 at 17:16