动态

详情 返回 返回

rust學習二十.10、RUST高級類型之新類型模式和類型別名 - 动态 详情

這兩個內容都比較容易理解。

一、新類型(newtype)模式

注意,這裏説的是一種編程模式,不是説有一個叫newtype的類型。

這種編程模式的含義:為某個類型作個封裝,構建一個新的類型,以便繞過某些束縛,從而達成特定目的。

目的如下:

a.用於抽象掉一些類型的實現細節

b.可以隱藏其內部的泛型類型

c.實現曲線救國

一個典型的例子,利用新類型繞過孤兒規則。

二、類型別名

語法

type  xxx=現有的類型

看起來有點像特質中的關聯類型定義。

附:特質關聯類型實現示例

impl Fight for Person {
    type Item = Animal;
    fn attack(&self, other: &self::Item) {
        println!(
            "{}歲{}(性別:{}) 攻擊了 {}歲{}",
            self.age,
            self.name,
            self.sex,
            other.age,
            other.name
        );
    }
    fn defend<T: Danger>(&self, danger: &T) {
        println!("{},{}歲{}(性別:{}) 奮起併力圖戰勝它們",danger.happen(), self.age, self.name, self.sex);
    }
}

要點

a.簡化類型書寫
b.使得代碼更容易閲讀
c.也更方便維護,例如如果許多方法都要求用同個類型,那麼這樣定義之後就不容易搞錯,
  作用上和java中定義的枚舉常量一個道理。

在rust的標準庫中,有不少的類型別名,例如Result<T,E>等。

定義説明

a.可以為別名定義別名

b.沒有明確的別名層級限定,意思就是你定義了別名a,然後基於a定義b,依次類推,可以定義type n=m..  .有多少層級限定不知道,不過定義個2次應該沒有問題的。

 

rust的類型別名是一種類似Microsoft SqlServer自定義類型的東西。

在 SQL Server 中,可以通過 用户定義數據類型(User-Defined Data Types, UDT) 創建自定義類型,本質上是基於系統數據類型的別名,並附加約束或默認值。

例如:

-- 創建類型:限制長度並校驗格式
CREATE TYPE dbo.Email 
FROM VARCHAR(255) 
NOT NULL 
WITH CHECK (CHARINDEX('@', value) > 0);

-- 使用類型
CREATE TABLE Users (
    UserID INT PRIMARY KEY,
    UserEmail dbo.Email
);

-- 測試插入
INSERT INTO Users VALUES (1, 'test@example.com');  -- 成功
INSERT INTO Users VALUES (2, 'invalid-email');     -- 失敗,觸發 CHECK 約束

只要做過數據庫設計,就知道這個東西多好用! 好記、容易保證相同的屬性使用相同的類型、維護也非常容易。

如果修改了type,就會發現有的時候,這真是一個絕妙的注意。

這種好東西在postgresql和mysql(8以上)都有類似的實現。

 

所以,毫無疑問,在rust中這是一個絕妙主意,因為我們都知道rust的類型之複雜醜陋是出名的,有的時候讓人心煩,又會耗費很多時間打字,而又了別名就會在某些情況下,大大改善這個現象。

 

三、新類型示例

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是外部包類型。

四、類型別名示例

struct Person {
    name: String,
    age: u8,
}
type Teacher = Person;
type Student = Person;
type GoodPeople = Student;
type Thunk = Box<dyn Fn() + Send + 'static>;

fn print_student(p: &Student) {
    println!("name={},age={}", p.name, p.age);
}

fn print_me(p: &GoodPeople) {
    println!("name={},age={}", p.name, p.age);
}

fn main() {
    let f: Thunk = Box::new(|| println!("hi"));
    //應為Thunk是Box類型,已經實現了Deref特質,它可以自動解引用,所以可以直接調用。
    f();
    //如果想顯式調用,可以這樣寫:
    (*f)();
    let p = Student {
        name: "張三".to_string(),
        age: 30,
    };
    print_student(&p);

    let g = GoodPeople {
        name: "lzf".to_string(),
        age: 99,
    };
    print_me(&g);
}
#[allow(unused)]
fn takes_long_type(f: Thunk) {
    // --snip--
}
#[allow(unused)]
fn returns_long_type() -> Thunk {
    // --snip--
    Box::new(|| {})
}

上例中,Student是Person別名,GoodPerson是Student的別名。

運行結果:

五、小結

1.類型別名的確是一個很好的東西

2.只要寫過代碼,就知道它能讓代碼更簡單、易讀、易維護

 

Add a new 评论

Some HTML is okay.