動態

詳情 返回 返回

rust學習二十.8、RUST特質的限定,實為對類型的限定 - 動態 詳情

有的時候,可能希望使用的特質已經實現了其它特質(看後面可以知道,實際是要求相關類型實現了其它特質)。

RUST支持為特質(trait)指定限定的特質。

例如我們定義特質A,之後定義了類型T,這個時候還希望T已經實現了特質TC

在rust中就是這個語法:

trait tx:t1

trait tx:t1+t2..+tn

根據相關數據的例子和説明,需要特別注意,具體的實現都是依賴於類型,而不是特質。

一、示例1

use std::fmt;

struct Point {
    x: i32,
    y: i32,
}
trait Copy{
    fn copy(&self) -> Self;
}
trait OutlinePrint: fmt::Display+Copy{
    fn outline_print(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {output} *");
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

impl OutlinePrint for Point {}
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}
impl Copy for Point {
    fn copy(&self) -> Self {
            Point { x: self.x, y: self.y }
    }
}

fn main() {
    let p = Point { x: 10, y: 20 };
    p.outline_print();
    let c=p.copy();
    c.outline_print();
}

在本例中Point必須實現特質Copy和Display和OutlinePrint,注意OutlinePrint的定義:

trait OutlinePrint: fmt::Display+Copy

多個特質之間用+號連接。

輸出如下:

 

二、示例2-在方法中使用特質有關方法

把以上的例子稍微修改下:

use std::fmt;

struct Point {
    x: i32,
    y: i32,
}
trait Copyable {
    fn copy(&self) -> Self;
}
trait OutlinePrint: fmt::Display + Copyable +Sized{
    fn outline_print(&self) {
        // 先創建副本
        let copied = self.copy();
        // 然後將副本轉換為字符串
        let output = copied.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

impl OutlinePrint for Point {}
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}
impl Copyable for Point {
    fn copy(&self) -> Self {
            Point { x: self.x, y: self.y }
    }
}

fn main() {
    let p = Point { x: 10, y: 20 };
    p.outline_print();
}

本例中,首先為OutlinePrint增加一個限定Sized,其次方法outline_print是先copy再to_string.

如果OutlinePrint不添加一個Sized,那麼會提示語句 let copied=self.copy()報錯:doesn't have a size known at compile-time

rustc的給出的建議是:fn outline_print(&self) where Self: Sized  ,即為方法outline_print的參數添加限定(這是我們習慣的方式)

為什麼Point不需要實現Sized?這是因為Point的大小是確定的,其次編譯器會為此類類型隱式實現

輸出略。

三、示例3-如果不使用特質的限定

由於可以為方法的參數進行限定,我們很容易想到其實可以只對參數限定即可。

為了節約篇幅,這裏只把核心的內容貼出:

trait OutlinePrint{
    fn outline_print(&self)
    where Self: fmt::Display + Copyable+Sized
     {
        // 先創建副本
        let copied = self.copy();
        // 然後將副本轉換為字符串
        let output = copied.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

輸出:

四、小結

這種定義方式個人認為不是很符合一般思維方式,這是因為明明是對類型的限制,但是這種限制確寫在特質上。

例如在java等語言中,就沒有這種方式。

個人更加傾向於採用示例3的方式,尤其是在接觸多了類似JAVA之類的OOP語言後。

 

當然rust這種定義方式也有優點:如果相關特質方法的參數都是這種要求,那麼寫在特質上,的確會少打一些字。

所以,rust程序員可以根據需要來決定限定方式,某種程度上rust為我們提供了方便性和靈活性。

 

Add a new 評論

Some HTML is okay.