<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # Traits 你還記得`impl`關鍵字嗎,曾用[方法語法](http://doc.rust-lang.org/nightly/book/method-syntax.html)調用方法的那個? ~~~ struct Circle { x: f64, y: f64, radius: f64,}impl Circle { fnarea(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) }} ~~~ trait也很類似,除了我們用函數標記來定義一個trait,然后為結構體實現trait。例如: ~~~ struct Circle { x: f64, y: f64, radius: f64,}trait HasArea { fnarea(&self) -> f64;}impl HasArea for Circle { fnarea(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) }} ~~~ 如你所見,`trait`塊與`impl`看起來很像,不過我們沒有定義一個函數體,只是函數標記。當我們`impl`一個trait時,我們使用`impl Trait for Item`,而不是僅僅`impl Item`。 那么這有什么重要的呢?還記得我們使用泛型`inverse`函數得到的錯誤嗎? ~~~ error: binary operation `==` cannot be applied to type `T` ~~~ 我們可以用trait來約束我們的泛型。考慮下這個函數,它不能編譯并給出一個類似的錯誤: ~~~ fnprint_area<T>(shape: T) { println!("This shape has an area of {}", shape.area());} ~~~ Rust抱怨說: ~~~ fn print_area<T>(shape: T) { println!("This shape has an area of {}", shape.area());} ~~~ 因為`T`可以是任何類型,我們不能確定它實現了`area`方法。不過我們可以在泛型`T`添加一個_trait約束_(_trait constraint_),來確保它實現了對應方法: ~~~ fnprint_area<T: HasArea>(shape: T) { println!("This shape has an area of {}", shape.area());} ~~~ `<T: HasArea>`語法是指`any type that implements the HasArea trait`(任何實現了`HasArea`trait的類型)。因為trait定義了函數類型標記,我們可以確定任何實現`HasArea`將會擁有一個`.area()`方法。 這是一個擴展的例子演示它如何工作: ~~~ trait HasArea { fnarea(&self) -> f64;}struct Circle { x: f64, y: f64, radius: f64,}impl HasArea for Circle { fnarea(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) }}struct Square { x: f64, y: f64, side: f64,}impl HasArea for Square { fnarea(&self) -> f64 { self.side * self.side }}fnprint_area<T: HasArea>(shape: T) { println!("This shape has an area of {}", shape.area());}fnmain() { let c = Circle { x: 0.0f64, y: 0.0f64, radius: 1.0f64, }; let s = Square { x: 0.0f64, y: 0.0f64, side: 1.0f64, }; print_area(c); print_area(s);} ~~~ 這個程序會輸出: ~~~ This shape has an area of 3.141593This shape has an area of 1 ~~~ 如你所見,`print_area`現在是泛型的了,并且確保我們傳遞了正確的類型。如果我們傳遞了錯誤的類型: ~~~ print_area(5); ~~~ 我們會得到一個編譯時錯誤: ~~~ error: failed to find an implementation of trait main::HasArea for int ~~~ 目前為止,我們只在結構體上添加trait實現,不過你為任何類型實現一個trait。所以技術上講,你可以在`i32`上實現`HasArea`: ~~~ trait HasArea { fnarea(&self) -> f64;}impl HasArea for i32 { fnarea(&self) -> f64 { println!("this is silly"); *self as f64 }}5.area(); ~~~ 在基本類型上實現方法被認為是不好的設計,即便這是可以的。 這看起來有點像狂野西部(Wild West),不過這還有兩個限制來避免情況失去控制。第一是如果trait并不定義在你的作用域,它并不能實現。這是個例子:標準庫提供了一個[`Write`](http://doc.rust-lang.org/nightly/std/io/trait.Write.html)trait來為`File`增加額外的功能,為了進行文件I/O。默認,`File`并不會有這個方法: ~~~ let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");let result = f.write("whatever".as_bytes()); ~~~ 這里是錯誤: ~~~ error: type `std::fs::File` does not implement any method in scope named `write`let result = f.write(b”whatever”); ^~~~~~~~~~~~~~~~~~ ~~~ 我們需要先`use``Write`trait: ~~~ use std::io::Write;let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");let result = f.write("whatever".as_bytes()); ~~~ 這樣就能無錯誤的編譯了。 這意味著即使有人做了像給`int`增加函數這樣的壞事,它也不會影響你,除非你`use`了那個trait。 這還有一個實現trait的限制。不管是trait還是你寫的`impl`都只能在你自己的包裝箱內生效。所以,我們可以為`i32`實現`HasArea`trait,因為`HasArea`在我們的包裝箱中。不過如果我們想為`i32`實現`Float`trait,它是由Rust提供的,則無法做到,因為這個trait和類型都不在我們的包裝箱中。 關于trait的最后一點:帶有trait限制的泛型函數是_單態_(_monomorphization_)(mono:單一,morph:形式)的,所以它是_靜態分發_(_statically dispatched_)的。這是神馬意思?查看[trait對象](http://doc.rust-lang.org/nightly/book/trait-objects.html)來了解更多細節。 ### 多trait限定(Multiple trait bounds) 你已經見過你可以用一個trait限定一個泛型類型參數: ~~~ fnfoo<T: Clone>(x: T) { x.clone();} ~~~ 如果你需要多于1個限定,以可以使用`+`: ~~~ use std::fmt::Debug;fnfoo<T: Clone + Debug>(x: T) { x.clone(); println!("{:?}", x);} ~~~ `T`現在需要實現`Clone`和`Debug`。 ### where從句(Where clause) 編寫只有少量泛型和trait的函數并不算太糟,不過當它們的數量增加,這個語法就看起來比較詭異了: ~~~ use std::fmt::Debug;fnfoo<T: Clone, K: Clone + Debug>(x: T, y: K) { x.clone(); y.clone(); println!("{:?}", y);} ~~~ 函數的名字在最左邊,而參數列表在最右邊。限制寫在中間。 Rust有一個解決方案,它叫“where從句”: ~~~ use std::fmt::Debug;fnfoo<T: Clone, K: Clone + Debug>(x: T, y: K) { x.clone(); y.clone(); println!("{:?}", y);}fnbar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug { x.clone(); y.clone(); println!("{:?}", y);}fnmain() { foo("Hello", "world"); bar("Hello", "workd");} ~~~ `foo()`使用我們剛才的語法,而`bar()`使用`where`從句。所有你所需要做的就是在定義參數時省略限制,然后在參數列表后加上一個`where`。對于很長的列表,你也可以加上空格: ~~~ use std::fmt::Debug;fnbar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug { x.clone(); y.clone(); println!("{:?}", y);} ~~~ 這種靈活性可以使復雜情況變得簡潔。 `where`也比基本語法更強大。例如: ~~~ trait ConvertTo<Output> { fnconvert(&self) -> Output;}impl ConvertTo<i64> for i32 { fnconvert(&self) -> i64 { *self as i64 }}// can be called with T == i32fnnormal<T: ConvertTo<i64>>(x: &T) -> i64 { x.convert()}// can be called with T == i64fninverse<T>() -> T // this is using ConvertTo as if it were "ConvertFrom<i32>" where i32: ConvertTo<T> { 1i32.convert()} ~~~ 這突顯出了`where`從句的額外的功能:它允許限制的左側可以是任意類型(在這里是`i32`),而不僅僅是一個類型參數(比如`T`)。 ### 默認方法(Default methods) 關于trait還有最后一個我們需要講到的功能。它簡單到只需我們展示一個例子: ~~~ trait Foo { fnbar(&self); fnbaz(&self) { println!("We called baz."); }} ~~~ `Foo`trait的實現者需要實現`bar()`,不過并不需要實現`baz()`。它會使用默認的行為。你也可以選擇覆蓋默認行為: ~~~ struct UseDefault;impl Foo for UseDefault { fnbar(&self) { println!("We called bar."); }}struct OverrideDefault;impl Foo for OverrideDefault { fnbar(&self) { println!("We called bar."); } fnbaz(&self) { println!("Override baz!"); }}let default = UseDefault;default.baz(); // prints "We called bar."let over = OverrideDefault;over.baz(); // prints "Override baz!" ~~~ ### 繼承(Inheritance) 有時,實現一個trait要求實現另一個trait: ~~~ trait Foo { fn foo(&self);}trait FooBar : Foo { fn foobar(&self);} ~~~ `FooBar`的實現也必須實現`Foo`,像這樣: ~~~ struct Baz;impl Foo for Baz { fnfoo(&self) { println!("foo"); }}impl FooBar for Baz { fnfoobar(&self) { println!("foobar"); }} ~~~ 如果我們忘了實現`Foo`,Rust會告訴我們: ~~~ error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277] ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看