Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is 'self: Box<Self>' on a method? [duplicate]

I wanted to create a method that only works where the self parameter was an Rc. I saw that I could use Box, so I thought I might try to mimic how that works:

use std::rc::Rc;
use std::sync::Arc;

struct Bar;

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

fn main() {}

Yields these errors:

error[E0308]: mismatched method receiver
  --> a.rs:11:18
   |
11 |     fn ref_count(self: Rc<Bar>) {}
   |                  ^^^^ expected struct `Bar`, found struct `std::rc::Rc`
   |
   = note: expected type `Bar`
   = note:    found type `std::rc::Rc<Bar>`

error[E0308]: mismatched method receiver
  --> a.rs:12:25
   |
12 |     fn atomic_ref_count(self: Arc<Bar>) {}
   |                         ^^^^ expected struct `Bar`, found struct `std::sync::Arc`
   |
   = note: expected type `Bar`
   = note:    found type `std::sync::Arc<Bar>`

This is with Rust 1.15.1.

like image 254
Shepmaster Avatar asked Aug 23 '14 14:08

Shepmaster


2 Answers

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!)

like image 145
huon Avatar answered Oct 26 '22 23:10

huon


It's now possible to use arbitrary types for self, including Arc<Self>, but the feature is considered unstable and thus requires adding this crate attribute:

#![feature(arbitrary_self_types)]

Using feature crate attributes requires using nightly Rust.

like image 38
jbg Avatar answered Oct 26 '22 23:10

jbg