Какие типы допустимы для параметра self метода?

Я хотел создать метод, который работает только там, где параметр self был Rc. Я увидел, что могу использовать Box, поэтому подумал, что могу попытаться имитировать, как это работает:

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() {}

Выдает эти ошибки:

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>`

Это с Rust 1.15.1.


person Shepmaster    schedule 23.08.2014    source источник


Ответы (2)


До Rust 1.33 было всего четыре действительных получателя метода:

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() {}

Изначально в Rust не было этой явной self формы, только self, &self, &mut self и ~self (старое название Box). Это изменилось так, что только по значению и по ссылкам есть встроенный сокращенный синтаксис, поскольку они являются обычными случаями и имеют очень ключевые языковые свойства, в то время как все интеллектуальные указатели (включая Box) требуют явной формы.

Начиная с Rust 1.33, некоторые дополнительные выбранные типы доступны для использования как self:

  • Rc
  • Arc
  • Pin

Это означает, что исходный пример теперь работает:

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();
}

Однако обработка impl еще не была полностью обобщена для соответствия синтаксису, поэтому типы, созданные пользователем, по-прежнему не работают. Прогресс в этом направлении осуществляется под флагом функции arbitrary_self_types, и обсуждается проблема отслеживания 44874.

(Чего стоит ждать!)

person huon    schedule 23.08.2014
comment
Так что я могу разумно ожидать, что другие типы библиотек, кроме Box, будут поддерживаться в какой-то момент в будущем? - person Shepmaster; 23.08.2014
comment
Да, поддержка других типов указателей - основная причина изменения синтаксиса. - person huon; 23.08.2014
comment
Вернемся к этому много месяцев спустя; какие изменения вы знаете в этой области? Код как есть не компилируется, так что пока ничего очевидного. - person Shepmaster; 30.03.2016
comment
@Shepmaster см. Мой ответ ниже. - person jbg; 08.08.2018

Теперь можно использовать произвольные типы для self, включая Arc<Self>, но эта функция считается нестабильной и поэтому требует добавления этого атрибут crate:

#![feature(arbitrary_self_types)]

Использование feature атрибутов crate требует использования ночного Rust.

person jbg    schedule 08.08.2018
comment
Я бы добавил, что, несмотря на название, произвольные типы self не совсем произвольны, но должны (транзитивно) заменяться на Self. Итак, self: Arc<Self> и self: &Arc<Self> в порядке, а self: Vec<Self> - нет. (Конечно, детали могут быть изменены до стабилизации.) - person trentcl; 08.08.2018
comment
Этот ответ сейчас устарел. - person mcarton; 12.05.2020