ประเภทใดที่ถูกต้องสำหรับพารามิเตอร์ `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> ได้ แต่ฟีเจอร์นี้ถือว่าไม่เสถียร จึงจำเป็นต้องเพิ่ม แอตทริบิวต์ลัง:

#![feature(arbitrary_self_types)]

การใช้แอตทริบิวต์ลัง feature ต้องใช้สนิมทุกคืน

person jbg    schedule 08.08.2018
comment
ฉันจะเสริมว่าถึงแม้จะมีชื่อ แต่ประเภทตนเองตามอำเภอใจนั้นไม่ได้เป็นไปตามอำเภอใจ แต่ต้อง (สกรรมกริยา) ยกเลิกไปที่ Self ดังนั้น self: Arc<Self> และ self: &Arc<Self> ถือว่าใช้ได้ แต่ self: Vec<Self> ไม่ใช่ (แน่นอนว่ารายละเอียดอาจมีการเปลี่ยนแปลงก่อนที่จะมีเสถียรภาพ) - person trentcl; 08.08.2018
comment
คำตอบนี้ล้าสมัยแล้ว - person mcarton; 12.05.2020