"ประเภทพื้นฐาน" ใน Rust คืออะไร?


37

บางแห่งฉันหยิบคำว่า "ประเภทพื้นฐาน" (และคุณลักษณะของมัน#[fundamental]) และตอนนี้ฉันต้องการเรียนรู้เพิ่มเติมเกี่ยวกับมัน ฉันจำได้ว่ามันเกี่ยวกับการผ่อนคลายกฎการเชื่อมโยงกันในบางสถานการณ์ และฉันคิดว่าประเภทอ้างอิงเป็นประเภทพื้นฐานดังกล่าว

น่าเสียดายที่การค้นหาเว็บไม่ได้ทำให้ฉันอยู่ไกล การอ้างอิงสนิมไม่ได้พูดถึงมัน (เท่าที่ฉันเห็น) ฉันเพิ่งพบปัญหาเกี่ยวกับการทำสิ่งอันดับประเภทพื้นฐานและRFC ที่แนะนำแอตทริบิวต์ อย่างไรก็ตาม RFC มีย่อหน้าเดียวเกี่ยวกับประเภทพื้นฐาน:

  • #[fundamental]ประเภทFooเป็นหนึ่งที่ดำเนินการ Impl ผ้าห่มกว่าFooคือการเปลี่ยนแปลงที่จะหมด ตามที่อธิบายไว้&และ&mutเป็นพื้นฐาน แอ็ตทริบิวต์นี้จะถูกนำไปใช้Boxทำให้มีBox พฤติกรรมเหมือนกับ&และ&mutด้วยความเคารพต่อการเชื่อมโยงกัน

ฉันพบว่าถ้อยคำยากที่จะเข้าใจและรู้สึกว่าฉันต้องการความรู้เชิงลึกของ RFC แบบเต็มเพื่อทำความเข้าใจเกี่ยวกับประเภทพื้นฐานนี้ ฉันหวังว่าใครบางคนสามารถอธิบายประเภทพื้นฐานในแง่ที่ค่อนข้างง่ายกว่า (โดยไม่ต้องทำให้ง่ายขึ้นมากเกินไป) คำถามนี้ยังใช้เป็นความรู้ที่ง่ายต่อการค้นหา

เพื่อทำความเข้าใจประเภทพื้นฐานฉันต้องการตอบคำถามเหล่านี้ (นอกเหนือจากคำถามหลัก "พวกเขาคืออะไร" คำถาม: แน่นอน):

  • ประเภทพื้นฐานสามารถทำได้มากกว่าประเภทที่ไม่ใช่พื้นฐานหรือไม่?
  • ในฐานะผู้เขียนห้องสมุดฉันจะได้ประโยชน์จากการทำเครื่องหมายบางประเภทในบางวิธี#[fundamental]หรือไม่?
  • ประเภทใดจากภาษาหลักหรือไลบรารีมาตรฐานเป็นพื้นฐาน?

คำตอบ:


34

โดยปกติหากไลบรารีมีประเภททั่วไปFoo<T>ลังแบบดาวน์สตรีมจะไม่สามารถใช้คุณลักษณะได้แม้ว่าจะเป็นTจะเป็นประเภทโลคัลก็ตาม ตัวอย่างเช่น,

( crate_a)

struct Foo<T>(pub t: T)

( crate_b)

use crate_a::Foo;

struct Bar;

// This causes an error
impl Clone for Foo<Bar> {
    fn clone(&self) -> Self {
        Foo(Bar)
    }
}

สำหรับตัวอย่างที่เป็นรูปธรรมที่ทำงานบนสนามเด็กเล่น (นั่นคือให้ข้อผิดพลาด)

use std::rc::Rc;

struct Bar;

// This causes an error
// error[E0117]: only traits defined in the current crate
// can be implemented for arbitrary types
impl Default for Rc<Bar> {
    fn default() -> Self {
        Rc::new(Bar)
    }
}

(สนามเด็กเล่น)


ตามปกตินี้จะช่วยให้ผู้เขียนลังเพิ่มการใช้งาน (ครอบคลุม) ของลักษณะโดยไม่ทำลายลังขาลง เป็นสิ่งที่ยอดเยี่ยมในกรณีที่ไม่แน่ใจในตอนแรกว่าประเภทควรใช้คุณลักษณะเฉพาะ แต่ในภายหลังจะชัดเจนว่าควรใช้ num-traitsยกตัวอย่างเช่นเราอาจจะมีการเรียงลำดับของประเภทตัวเลขบางอย่างที่ตอนแรกไม่ใช้ลักษณะจาก คุณสมบัติเหล่านั้นสามารถเพิ่มได้ในภายหลังโดยไม่จำเป็นต้องเปลี่ยนการแตกหัก

อย่างไรก็ตามในบางกรณีผู้เขียนไลบรารีต้องการให้ลังดาวน์สตรีมสามารถใช้คุณลักษณะได้ด้วยตนเอง นี่คือที่#[fundamental]มาของแอ็ตทริบิวต์เมื่อวางบนชนิดคุณลักษณะใด ๆ ที่ไม่ถูกนำไปใช้ในปัจจุบันสำหรับประเภทนั้นจะไม่ถูกนำมาใช้ เป็นผลให้ลังดาวน์สตรีมสามารถใช้คุณลักษณะสำหรับประเภทนั้นตราบใดที่พารามิเตอร์ type เป็นโลคัล (มีกฎที่ซับซ้อนบางอย่างสำหรับการตัดสินใจว่าพารามิเตอร์ชนิดใดนับรวมอยู่ในนี้) เนื่องจากประเภทพื้นฐานจะไม่ใช้คุณลักษณะที่กำหนดคุณลักษณะนั้นจึงสามารถนำไปใช้ได้อย่างอิสระโดยไม่ก่อให้เกิดปัญหาการเชื่อมโยงกัน

ตัวอย่างเช่นBox<T>มีการทำเครื่องหมาย#[fundamental]ดังนั้นรหัสต่อไปนี้ (คล้ายกับRc<T>รุ่นด้านบน) ใช้งานได้ Box<T>ไม่ใช้Default(เว้นแต่จะมีTการดำเนินการDefault) ดังนั้นเราจึงสามารถสรุปได้ว่ามันจะไม่เกิดขึ้นในอนาคตเพราะBox<T>เป็นพื้นฐาน โปรดทราบว่าการดำเนินการDefaultสำหรับการBarจะทำให้เกิดปัญหาตั้งแต่นั้นมาการดำเนินการอยู่แล้วBox<Bar>Default

struct Bar;

impl Default for Box<Bar> {
    fn default() -> Self {
        Box::new(Bar)
    }
}

(สนามเด็กเล่น)


บนมืออื่น ๆ #[fundamental]ลักษณะนี้ยังสามารถทำเครื่องหมายด้วย สิ่งนี้มีความหมายสองอย่างสำหรับประเภทพื้นฐาน หากประเภทใดไม่ได้ใช้คุณลักษณะพื้นฐานในปัจจุบันก็สามารถสันนิษฐานได้ว่าประเภทนั้นจะไม่ดำเนินการในอนาคต (อีกครั้งยกเว้นการเปลี่ยนแปลงที่ทำลาย) ฉันไม่แน่ใจว่าวิธีนี้ใช้ในการปฏิบัติ ในรหัส (ลิงก์ด้านล่าง) FnMutมีการทำเครื่องหมายพื้นฐานพร้อมด้วยข้อความที่จำเป็นสำหรับ regex (บางอย่างเกี่ยวกับ&str: !FnMut) ฉันไม่พบตำแหน่งที่ใช้ในregexลังไม้หรือหากใช้ที่อื่น

ในทางทฤษฎีหากAddคุณลักษณะนั้นเป็นพื้นฐาน (ซึ่งได้มีการพูดคุยกัน) สิ่งนี้อาจถูกนำมาใช้เพื่อเพิ่มเติมระหว่างสิ่งที่ยังไม่มีอยู่ ตัวอย่างเช่นการเพิ่ม[MyNumericType; 3](จุด) ซึ่งอาจมีประโยชน์ในบางสถานการณ์ (แน่นอนว่าการสร้าง[T; N]พื้นฐานจะอนุญาตสิ่งนี้ด้วย)


ดั้งเดิมประเภทพื้นฐานมี&T, &mut T(ดูที่นี่สำหรับการสาธิตของชนิดดั้งเดิมทั่วไปทั้งหมด) ในไลบรารีมาตรฐานBox<T>และPin<T>ถูกทำเครื่องหมายเป็นพื้นฐาน

ลักษณะพื้นฐานในห้องสมุดมาตรฐานSized, Fn<T>, FnMut<T>, และFnOnce<T>Generator


โปรดทราบว่า#[fundamental]ขณะนี้แอตทริบิวต์ไม่เสถียร ปัญหาการติดตามเป็นปัญหา #


1
คำตอบที่ดี! เกี่ยวกับชนิดดั้งเดิม: มีเพียงไม่กี่คนทั่วไปชนิดดั้งเดิม: &T, &mut T, *const T, *mut T, [T; N], [T], fnตัวชี้และ tuples และทดสอบพวกเขาทั้งหมด (โปรดบอกฉันว่ารหัสนี้ไม่สมเหตุสมผล) ดูเหมือนว่าการอ้างอิงเป็นประเภทพื้นฐานดั้งเดิมเท่านั้น น่าสนใจ ฉันสนใจที่จะรู้เหตุผลว่าทำไมคนอื่นถึงไม่โดยเฉพาะอย่างยิ่งตัวชี้ที่ดิบ แต่นั่นไม่ใช่ขอบเขตของคำถามนี้ฉันเดา
Lukas Kalbertodt

1
@ LukasKalbertodt ขอบคุณสำหรับข้อมูลเกี่ยวกับประเภทดั้งเดิม ฉันเพิ่มในการทดสอบของคุณ สำหรับเหตุผลเกี่ยวกับการอ้างอิงกับพอยน์เตอร์ให้ตรวจสอบความคิดเห็นนี้ในคำขอดึง RFC
SCappella

การอ้างอิงไม่ได้บันทึกคุณลักษณะที่ไม่เสถียรดังนั้นนั่นเป็นสาเหตุที่คุณไม่พบที่นั่น
Havvy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.