What types are valid for the `self` parameter of a method?

Before Rust 1.33, there are only four valid method receivers:

struct Foo;

impl Foo {
    fn by_val(self: Foo) {} // a.k.a. by_val(self)
    fn by_ref(self: &Foo) {} // a.k.a. by_ref(&self)
    fn by_mut_ref(self: &mut Foo) {} // a.k.a. by_mut_ref(&mut self)
    fn by_box(self: Box<Foo>) {} // no short form
}

fn main() {}

Originally, Rust didn’t have this explicit self form, only self, &self, &mut self and ~self (the old name for Box). This changed so that only by-value and by-references have the short-hand built-in syntax, since they are the common cases, and have very key language properties, while all smart pointers (including Box) require the explicit form.

As of Rust 1.33, some additional selected types are available for use as self:

  • Rc
  • Arc
  • Pin

This means that the original example now works:

use std::{rc::Rc, sync::Arc};

struct Bar;

impl Bar {
    fn consuming(self)                  { println!("self") }
    fn reference(&self)                 { println!("&self") }
    fn mut_reference(&mut self)         { println!("&mut self") }
    fn boxed(self: Box<Bar>)            { println!("Box") }
    fn ref_count(self: Rc<Bar>)         { println!("Rc") }
    fn atomic_ref_count(self: Arc<Bar>) { println!("Arc") }
}

fn main() {
    Bar.consuming();
    Bar.reference();
    Bar.mut_reference();
    Box::new(Bar).boxed();
    Rc::new(Bar).ref_count();
    Arc::new(Bar).atomic_ref_count();
}

However, the impl handling hasn’t yet been fully generalised to match the syntax, so user-created types still don’t work. Progress on this is being made under the feature flag arbitrary_self_types and discussion is taking place in the tracking issue 44874.

(Something to look forward to!)

Leave a Comment