动态

详情 返回 返回

rust學習二十.9、RUST繞過孤兒規則實現特質和包裝器缺點 - 动态 详情

回憶下孤兒規則:

1.只有當一個trait或類型在當前的crate中定義時,才能為外部類型實現該trait。 沒有限定是特質還是類型

反過來,如果特質和類型都是外部,那麼不能在當前單元包實現

2.例外情況-std中特質是例外。大體驗證了凡事都有例外

孤兒規則的目的:避免編譯器無法確定應該用哪一個實現。

這個目的很容易理解。無論是否叫孤兒,絕大部分語言中都是類似的規則-不允許一個類型實現接口/特質的時候,有多處不一樣代碼。

 

書本上主要討論如何繞過孤兒規則,方案就是:對外部類型進行封裝,構建一個新的本地類型,然後就可以實現本地類型的外部特質,從而間接實現外部類型的外部特質。

不過這本質上是一種繞過問題的解決方案,在有些場合中也可以將就使用。在rust中有提到相對直接的解決方法,不過本文暫不論述。

一、孤兒規則示例

如下圖,這是一個包含了三個單元的工作空間:

其中wsmain是二進制單元,對於wsmain而言,student和teacher兩個都是外部crate,看wsmain的Cargo.toml就明白了:

[package]
name = "wsmain"
version.workspace=true
edition.workspace=true

[dependencies]
student={path="../student"}
teacher={path="../teacher"}

本例中分別在teacher包中定義了特質Print,並在wsmain中嘗試為Teacherinfo(teacher中的struct)實現Print,為了節省篇幅,放在一起:

//在teacher包
pub trait Print{
    fn print(&self);
}
pub struct Teacherinfo{
    pub name: String,
    pub age: u8,
    pub gender: String,
    pub position: String
}
//在wsmain二進制單元包中
impl Print for Teacherinfo{
    fn print(&self){
        println!("{}",self.name);
    }
}

如果你嘗試運行,那麼回得到如下提示:

二、用包裝類繞過孤兒規則

何謂包裝類,此處不介紹,直接看示例代碼:

use student::*;
use teacher::*;

fn main() {
    let lml = Studentinfo {
        name: String::from("lml"),
        age: 18,
        gender: String::from("女"),
        no: String::from("12101"),
    };
    print_student(&lml);
    lml.learn();
    lml.sleep();

    let lu = Teacherinfo {
        name: String::from("lu"),
        age: 46,
        gender: String::from("男"),
        position: String::from("教研組長"),
    };
    lu.teach_student(&lml);
    print_teacher(&lu);
    let _me = Box::new(String::from("中國"));

    let my_lu = MyTeacherinfo(lu);
    my_lu.print();
}

struct MyTeacherinfo(Teacherinfo);
impl Print for MyTeacherinfo {
    fn print(&self) {
        println!(
            "教師基本信息-姓名:{},年齡:{},性別:{},職位:{}",
            self.0.name, self.0.age, self.0.gender, self.0.position
        );
    }
}

在這個示例中,定義了一個新的結構,成員只包含一個Teacherinfo。用的是使用元組定義結構的方式。

看運行結果:

三、小結

這種利用包裝模式繞過的方法有時候也能起到作用,只不過,我更願意聽到直面問題的方案。

利用包裝模式是rust直常常提到的newtype模式的一種。所謂newtype,大概可以這樣理解:基於特定構建一個新的類型,這樣可以繞過一些問題,達成一些目的。

用包裝器來繞過,還是有些小麻煩,倒也不是不能用!

 

Add a new 评论

Some HTML is okay.