StarknetAstro

StarknetAstro

17_Cairo中的Trait

17_Cairo 中的 Trait#

此文章使用的 Cairo 編譯器版本:2.0.0-rc0。因為 Cairo 正在快速更新,所以不同版本的語法會有些許不同,未來將會將文章內容更新到穩定版本。

前面我們已經寫了很多使用到 trait 的程式碼,我們現在就來將 trait 的用法總結一下。

Trait 的字面意思是” 特徵”,相當於其他程式語言的介面(interface)。可以使用 trait 定義一組方法作為這個 trait 具備的特徵的具體內容,任何一個型別都可以實現這個 trait 中所有的方法,也就是擁有這個 trait 的特徵。

基本用法#

結構體實現一個 trait 時,需要實現 trait 中所有的方法,否則就不能算作為實現了這個 trait,編譯的時候也會出錯。看看一個例子:

use debug::PrintTrait;

#[derive(Copy, Drop)]
struct Rectangle {
    width: u64,
    high: u64
}

trait ShapeGeometry {
    fn new(width: u64, high: u64) -> Rectangle;
    fn boundary(self: @Rectangle) -> u64;
    fn area(self: @Rectangle) -> u64;
}

// 這裡實現3個函數的邏輯
impl RectangleGeometryImpl of ShapeGeometry {
    fn new(width: u64, high: u64) -> Rectangle {
        Rectangle { width, high }
    }

    fn boundary(self: @Rectangle) -> u64 {
        2 * (*self.high + *self.width)
    }
    fn area(self: @Rectangle) -> u64 {
        *self.high * *self.width
    }
}

fn main() {
	// 這裡直接使用 impl 呼叫 new 方法
    let r = RectangleGeometryImpl::new(10, 20);
    
    // 這裡使用 結構體呼叫 boundary 和 area 方法
    r.boundary().print();
    r.area().print();

    // 使用 impl 直接呼叫 area 方法
    RectangleGeometryImpl::area(@r).print();
}

以上定義了一個名為 Rectangle 的結構體,接著定義了一個名為 ShapeGeometry 的 trait,trait 中包含三個方法的簽名: newboundaryarea 。那麼我們要為 結構體 Rectangle 實現 trait ShapeGeometry ,就需要將 trait 中的 3 個函數的邏輯都寫在 impl 中。

另外,我們在 main 函數中可以看到,我們還可以直接使用 impl 呼叫成員函數

泛型 trait#

上面的例子中,trait 裡面寫明了 Rectangle 型別,那麼這個 trait 就只可以被 Rectangle 實現。如果遇到多個型別有同一個 trait 特徵的場景,就需要使用到泛型 trait。

use debug::PrintTrait;

#[derive(Copy, Drop)]
struct Rectangle {
    height: u64,
    width: u64,
}

#[derive(Copy, Drop)]
struct Circle {
    radius: u64
}

// 這個泛型 trait 可以被多個struct實現
trait ShapeGeometryTrait<T> {
    fn boundary(self: T) -> u64;
    fn area(self: T) -> u64;
}

// 被 Rectangle 型別實現
impl RectangleGeometryImpl of ShapeGeometryTrait<Rectangle> {
    fn boundary(self: Rectangle) -> u64 {
        2 * (self.height + self.width)
    }
    fn area(self: Rectangle) -> u64 {
        self.height * self.width
    }
}

// 被 Circle 型別實現
impl CircleGeometryImpl of ShapeGeometryTrait<Circle> {
    fn boundary(self: Circle) -> u64 {
        (2 * 314 * self.radius) / 100
    }
    fn area(self: Circle) -> u64 {
        (314 * self.radius * self.radius) / 100
    }
}

fn main() {
    let rect = Rectangle { height: 5, width: 7 };
    rect.area().print(); // 35
    rect.boundary().print(); // 24

    let circ = Circle { radius: 5 };
    circ.area().print(); // 78
    circ.boundary().print(); // 31
}

上面我們定義了 ShapeGeometryTrait<T> trait,它同時被 RectangleCircle 兩個結構體實現,並且在 main 函數中使用相同名字的成員方法。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。