<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Rust從入門到精通07-trait

      Rust 語言中,trait 是一個(gè)非常重要的概念,可以包含:函數(shù)、常量、類型等。

      通俗一點(diǎn)理解,trait 以一種抽象的方式定義共享的行為,可以被認(rèn)為是一些語言的接口,但是與接口也有一定區(qū)別,下面會(huì)介紹。

      1、成員方法

      trait 中可以定義方法。

      trait Shape {
          fn area(&self) -> f64;
      }
      

      我們?cè)谝粋€(gè)名為 Shape 的 trait 中定義了一個(gè)方法 area。

      1.1 方法參數(shù)

      看上面定義的 Shape,方法的參數(shù)是 &self。

      其實(shí)對(duì)于每個(gè) trait 都有一個(gè)隱藏的類型 Self(大寫的 S),代表實(shí)現(xiàn)此 trait 的具體類型。

      Rust 中 Self 和 self 都是關(guān)鍵字,大寫的Self是類型名,小寫的 self 是變量名。

      其實(shí) area(&self) 等價(jià)于 area(self : &Self),只不過 rust 提供了簡(jiǎn)化的寫法。

      下面幾種情況都是等價(jià)的。

      trait T {
          fn method1(self : Self);
          fn method2(self : &Self);
          fn method3(self : &mut Self);
      }
      //等價(jià)于下面方法定義
      trait T {
          fn method1(self);
          fn method2(&self);
          fn method3(&mut self);
      }
      

      1.2 調(diào)用實(shí)例

      可以參考如下例子:

      trait Shape {
          fn area(&self) -> f64;
      }
      
      struct Circle {
          radius : f64,
      }
      
      impl Shape for Circle {
          // Self 的類型就是 Circle
          fn area(self : &Self) -> f64{
              // 可以通過self.radius訪問成員變量
              std::f64::consts::PI * self.radius * self.radius
          }
      }
      
      fn main() {
          let circle = Circle{ radius : 2f64};
          println!("The area is {}",circle.area())
      
      }
      

      ①、通過 self.成員變量 來訪問成員變量;

      ②、通過 實(shí)例.成員方法 來調(diào)用成員方法;

      2、匿名 trait

      impl Circle {
          fn get_radius(&self) -> f64 {
              self.radius
          }
      }
      

      impl 關(guān)鍵字后面直接接類型,沒有 trait 的名字。

      可以將上面代碼看成是為 Circle 實(shí)現(xiàn)了一個(gè)匿名的 trait。

      3、 靜態(tài)方法

      靜態(tài)方法:第一個(gè)參數(shù)不是 self 參數(shù)的方法。

      impl Circle {
          // 普通方法
          fn get_radius(&self) -> f64 {
              self.radius
          }
      
          // 靜態(tài)方法
          fn get_area(this : &Self) ->f64 {
              std::f64::consts::PI * this.radius * this.radius
          }
      }
      
      fn main() {
          let c = Circle{ radius : 2f64};
          // 調(diào)用普通方法
          println!("The radius is {}",c.radius);
          // 調(diào)用靜態(tài)方法
          println!("The area is {}",Circle::get_area(&c))
      
      }
      

      注意和普通方法的區(qū)別,參數(shù)命名不同,以及調(diào)用方式不同(普通方法是小數(shù) 實(shí)例.方法 ,靜態(tài)方法是 類型::方法 )。

      靜態(tài)方法的調(diào)用可以 Type::FunctionName()。

      4、擴(kuò)展方法

      利用 trait 給其它類型添加方法。

      比如我們給內(nèi)置類型 i32 添加一個(gè)方法:

      // 擴(kuò)展方法
      trait Double {
          fn double(&self) -> Self;
      }
      impl Double for i32 {
          fn double(&self) -> i32{
              self * 2
          }
      }
      
      fn main() {
          let x : i32 = 10.double();
          println!("x double is {}",x);//20
      
      }
      

      5、泛型約束

      在Rust中,靜態(tài)分發(fā)(Static Dispatch)和動(dòng)態(tài)分發(fā)(Dynamic Dispatch)是用于選擇和調(diào)用函數(shù)的兩種不同的機(jī)制。

      5.1 靜態(tài)分發(fā)

      在編譯時(shí)確定函數(shù)調(diào)用的具體實(shí)現(xiàn)。

      它通過在編譯階段解析函數(shù)調(diào)用并選擇正確的函數(shù)實(shí)現(xiàn),從而實(shí)現(xiàn)高效的調(diào)用。

      靜態(tài)分發(fā)通常適用于使用泛型的情況,其中編譯器可以根據(jù)具體的類型參數(shù)確定調(diào)用的函數(shù)。

      fn main() {
          fn myPrint<T: ToString>(v: T) {
              v.to_string();
          }
          
          let c = 'a';
          let s = String::from("hello");
          
          myPrint::<char>(c);
          myPrint::<String>(s);
      }
      

      等價(jià)于:

      fn myPrint(c:char){
          c.to_string();
      }
      fn myPrint(str:String){
          str.to_string();
      }
      

      5.2 動(dòng)態(tài)分發(fā)

      在運(yùn)行時(shí)根據(jù)對(duì)象的實(shí)際類型來選擇函數(shù)的實(shí)現(xiàn)。

      它適用于使用trait對(duì)象(通過使用dyn關(guān)鍵字)的情況,其中編譯器在編譯階段無法確定具體的函數(shù)實(shí)現(xiàn)。

      在運(yùn)行時(shí),程序會(huì)根據(jù)trait對(duì)象所包含的實(shí)際類型來動(dòng)態(tài)地選擇要調(diào)用的函數(shù)。

      動(dòng)態(tài)分發(fā)提供了更大的靈活性,但相對(duì)于靜態(tài)分發(fā),它可能會(huì)帶來一些運(yùn)行時(shí)開銷。

      下面代碼分別演示靜態(tài)分發(fā)和動(dòng)態(tài)分發(fā)的區(qū)別:

      trait Animal {
          fn make_sound(&self);
      }
      
      struct Cat;
      struct Dog;
      
      impl Animal for Cat {
          fn make_sound(&self) {
              println!("Meow!");
          }
      }
      
      impl Animal for Dog {
          fn make_sound(&self) {
              println!("Woof!");
          }
      }
      
      fn static_dispatch(animal: &impl Animal) {
          animal.make_sound();
      }
      
      fn dynamic_dispatch(animal: &dyn Animal) {
          animal.make_sound();
      }
      
      fn main() {
          let cat = Cat;
          let dog = Dog;
      
          // 靜態(tài)分發(fā)
          static_dispatch(&cat);
          static_dispatch(&dog);
      
          // 動(dòng)態(tài)分發(fā)
          dynamic_dispatch(&cat as &dyn Animal);
          dynamic_dispatch(&dog as &dyn Animal);
      }
      

      5、一致性原則

      一致性原則,也稱為孤兒原則(Orphan Rule):

      Impl 塊要么與 trait 塊的聲明在同一個(gè) crate 中,要么與類型的聲明在同一個(gè) crate 中。

      孤兒原則(Orphan Rule)是Rust語言中的一項(xiàng)重要設(shè)計(jì)原則,它有助于確保trait實(shí)現(xiàn)的可控性和可追溯性。遵守孤兒原則可以提高代碼的可讀性和可維護(hù)性,并降低潛在的沖突和混亂。

      也就是說如果 trait 來自外部,而且類型也來自外部 crate,編譯器是不允許你為這個(gè)類型 impl 這個(gè) trait。它們當(dāng)中至少有一個(gè)是在當(dāng)前 crate 中定義的。

      比如下面兩種情況都是可以的:

      use std::fmt::Display;
      
      struct A;
      impl Display for A {}
      
      trait TraitA {}
      impl TraitA for u32 {}
      

      但是下面這種情況就不可以:

      use std::fmt::Display;
      
      impl Display for u32 {}
      

      這也給我們提供了一個(gè)標(biāo)準(zhǔn):上游開發(fā)者在寫庫的時(shí)候,一些比較常用的標(biāo)準(zhǔn) trait,如 Display/Debug/ToString/Default 等,應(yīng)該盡可能的提供好。

      否則下游使用這個(gè)庫的開發(fā)者是沒法幫我們實(shí)現(xiàn)這些 trait 的。

      6、trait 和 接口區(qū)別

      開篇我們說為了便于理解 trait,可以想象為其它語言,比如Java中的接口。但是實(shí)際上他們還是有很大的區(qū)別的。

      因?yàn)?rust 是一種用戶可以對(duì)內(nèi)存有著精確控制的強(qiáng)類型語言。在目前 Rust 版本中規(guī)定:

      函數(shù)傳參類型,返回值類型等都是要在編譯期確定大小的。

      而 trait 本身既不是具體類型,也不是指針類型,它只是定義了針對(duì)類型的、抽象的約束。不同的類型可以實(shí)現(xiàn)同一個(gè) trait,滿足同一個(gè) trait 的類型可能具有不同的大小。

      所以 trait 在編譯階段沒有固定的大小,我們不能直接使用 trait 作為實(shí)例變量、參數(shù)以及返回值。

      類似下面的寫法都是錯(cuò)誤的:

      trait Shape {
          fn area(&self) -> f64;
      }
      
      impl Circle {
          //錯(cuò)誤1: trait(Shape)不能做參數(shù)的類型
          fn use_shape(arg : Shape){
      
          }
          //錯(cuò)誤2: trait(Shape)不能做返回值的類型
          fn ret_shape() -> Shape{
      
          }
      }
      fn main() {
          // 錯(cuò)誤3:trait(Shape)不能做局部變量的類型
          let x : Shape = Circle::new();
      }
      

      可以看到編譯器的錯(cuò)誤提示:

      7、derive

      Rust 標(biāo)準(zhǔn)庫內(nèi)部實(shí)現(xiàn)了一些邏輯較為固定的 trait,通過 derive 配置可以幫助我們自動(dòng) impl 某些 trait,而無需手動(dòng)編寫對(duì)應(yīng)的代碼。

      #[derive(Debug)]
      struct Foo {
          data : i32,
      }
      fn main() {
          let v1 = Foo{data : 0};
          println!("{:?}",v1)
      }
      

      加上 Debug 的trait 實(shí)現(xiàn),便于格式化打印 struct。

      [derive(Debug)] 等價(jià)于 impl Debug for Foo {}

      目前,Rust 支持的可以自動(dòng) derive 的 trait 有如下:

      Copy,Clone,Default,Hash,
      Debug,PartialEq,Eq,PartialOrd,
      Ord,RustcEncodable,RustcDecodable,
      FromPrimitive,Send,Sync
      

      8、標(biāo)準(zhǔn)庫中常見 trait

      在介紹 derive 時(shí),我們說明了內(nèi)置的一些 trait,這都是標(biāo)準(zhǔn)庫中比較常見的 trait,下面我們分別介紹這些 trait 是干什么的。

      8.1 Display 和 Debug

      可以分別看下源碼定義:

      【Display】

      pub trait Display {
          /// Formats the value using the given formatter.
          ///
          /// # Examples
          ///
          /// ```
          /// use std::fmt;
          ///
          /// struct Position {
          ///     longitude: f32,
          ///     latitude: f32,
          /// }
          ///
          /// impl fmt::Display for Position {
          ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          ///         write!(f, "({}, {})", self.longitude, self.latitude)
          ///     }
          /// }
          ///
          /// assert_eq!("(1.987, 2.983)",
          ///            format!("{}", Position { longitude: 1.987, latitude: 2.983, }));
          /// ```
          #[stable(feature = "rust1", since = "1.0.0")]
          fn fmt(&self, f: &mut Formatter<'_>) -> Result;
      }
      

      【Debug】

      pub trait Debug {
          /// Formats the value using the given formatter.
          ///
          /// # Examples
          ///
          /// ```
          /// use std::fmt;
          ///
          /// struct Position {
          ///     longitude: f32,
          ///     latitude: f32,
          /// }
          ///
          /// impl fmt::Debug for Position {
          ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          ///         f.debug_tuple("")
          ///          .field(&self.longitude)
          ///          .field(&self.latitude)
          ///          .finish()
          ///     }
          /// }
          ///
          /// let position = Position { longitude: 1.987, latitude: 2.983 };
          /// assert_eq!(format!("{:?}", position), "(1.987, 2.983)");
          ///
          /// assert_eq!(format!("{:#?}", position), "(
          ///     1.987,
          ///     2.983,
          /// )");
          /// ```
          #[stable(feature = "rust1", since = "1.0.0")]
          fn fmt(&self, f: &mut Formatter<'_>) -> Result;
      }
      

      ①、只有實(shí)現(xiàn)了 Display trait 的類型,才能夠用 {} 格式打印出來。

      ②、只有實(shí)現(xiàn)了 Debug trait 的類型,才能夠用{:?} {:#?} 格式打印出來。

      這兩者區(qū)別如下:

      1、Display 假定了這個(gè)類型可以用 utf-8 格式的字符串表示,它是準(zhǔn)備給最終用戶看的,并不是所有的類型都應(yīng)該或者能夠?qū)崿F(xiàn)這個(gè) trait。這個(gè) trait 的 fmt 應(yīng)該如何格式化字符串,完全取決于程序員自己,編譯器不提供自動(dòng) derive 的功能。

      2、標(biāo)準(zhǔn)庫中還有一個(gè)常用 trait 叫作 std::string::ToString,對(duì)于所有實(shí)現(xiàn)了 Display trait 的類型,都自動(dòng)實(shí)現(xiàn)了這個(gè) ToString trait 。它包含了一個(gè)方法 to_string(&self) -> String。任何一個(gè)實(shí)現(xiàn)了 Display trait 的類型,我們都可以對(duì)它調(diào)用 to_string() 方法格式化出一個(gè)字符串。

      3、Debug 則主要是為了調(diào)試使用,建議所有的作為 API 的“公開”類型都應(yīng)該實(shí)現(xiàn)這個(gè) trait,以方便調(diào)試。它打印出來的字符串不是以“美觀易讀”為標(biāo)準(zhǔn),編譯器提供了自動(dòng) derive 的功能。

      struct Color{
          r:u8,
          g:u8,
          b:u8,
      }
      
      impl Default for Color{
          fn default() -> Self{
              Self{r:0,g:0,b:0}
          }
      }
      

      等價(jià)于:

      #[derive(Default)]
      struct Color{
          r:u8,
          g:u8,
          b:u8,
      }
      

      8.2 ToString

      ToString 是 Rust 標(biāo)準(zhǔn)庫中定義的一個(gè)非常常用的 trait,它的目的是將任何實(shí)現(xiàn)了它的類型轉(zhuǎn)換為 String 類型的文本表示

      #[cfg_attr(not(test), rustc_diagnostic_item = "ToString")]
      #[stable(feature = "rust1", since = "1.0.0")]
      pub trait ToString {
          /// Converts the given value to a `String`.
          ///
          /// # Examples
          ///
          /// ```
          /// let i = 5;
          /// let five = String::from("5");
          ///
          /// assert_eq!(five, i.to_string());
          /// ```
          #[rustc_conversion_suggestion]
          #[stable(feature = "rust1", since = "1.0.0")]
          #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")]
          fn to_string(&self) -> String;
      }
      

      自動(dòng)實(shí)現(xiàn)

      雖然 ToString 是一個(gè) trait,但你幾乎不需要手動(dòng)實(shí)現(xiàn)它,因?yàn)闃?biāo)準(zhǔn)庫中已經(jīng)為所有實(shí)現(xiàn)了 Display 的類型,自動(dòng)實(shí)現(xiàn)了 ToString

      也就是說:

      實(shí)現(xiàn)了 Display ? 自動(dòng)擁有 .to_string() 方法。

      to_string() 本質(zhì)上等價(jià)于 format!("{}", value)。

      #[cfg(not(no_global_oom_handling))]
      #[stable(feature = "rust1", since = "1.0.0")]
      impl<T: fmt::Display + ?Sized> ToString for T {
          #[inline]
          fn to_string(&self) -> String {
              <Self as SpecToString>::spec_to_string(self)
          }
      }
      
      
      impl<T: fmt::Display + ?Sized> SpecToString for T {
          // A common guideline is to not inline generic functions. However,
          // removing `#[inline]` from this method causes non-negligible regressions.
          // See <https://github.com/rust-lang/rust/pull/74852>, the last attempt
          // to try to remove it.
          #[inline]
          default fn spec_to_string(&self) -> String {
              let mut buf = String::new();
              let mut formatter =
                  core::fmt::Formatter::new(&mut buf, core::fmt::FormattingOptions::new());
              // Bypass format_args!() to avoid write_str with zero-length strs
              fmt::Display::fmt(self, &mut formatter)
                  .expect("a Display implementation returned an error unexpectedly");
              buf
          }
      }
      

      8.3 ParitialEq/Eq

      在Rust中,PartialOrd、Ord、PartialEqEq是用于比較和排序的trait。通過使用derive宏,可以自動(dòng)為結(jié)構(gòu)體或枚舉實(shí)現(xiàn)這些trait的默認(rèn)行為。

      下面是對(duì)這些trait的簡(jiǎn)要解釋:

      1. PartialOrd trait:用于部分順序比較,即可以進(jìn)行比較但不一定可以完全排序。它定義了partial_cmp方法,用于比較兩個(gè)值并返回一個(gè)Option<Ordering>枚舉,表示比較結(jié)果。
      2. Ord trait:用于完全順序比較,即可以進(jìn)行完全排序。它是PartialOrd trait的超集,定義了cmp方法,用于比較兩個(gè)值并返回Ordering枚舉,表示比較結(jié)果。
      3. PartialEq trait:用于部分相等性比較。它定義了eq、nelt、le、gtge等方法,用于比較兩個(gè)值是否相等、不相等、小于、小于等于、大于、大于等于。
      4. Eq trait:用于完全相等性比較,即可以進(jìn)行完全相等性判斷。它是PartialEq trait的超集,無需手動(dòng)實(shí)現(xiàn),通過自動(dòng)實(shí)現(xiàn)PartialEq trait即可獲得Eq trait的默認(rèn)實(shí)現(xiàn)。

      Eq定義為PartialEq的subtrait

      #[derive(PartialEq, Debug)]    // 注意這一句
      struct Point {
          x: i32,
          y: i32,
      }
      fn example_assert(p1: Point, p2: Point) {
          assert_eq!(p1, p2);        // 比較
      }
      

      8.4 PartialOrd/Ord

      PartialOrd和PartialEq差不多,PartialEq只判斷相等或不相等,PartialOrd在這個(gè)基礎(chǔ)上進(jìn)一步判斷是小于、小于等于、大于還是大于等于??梢钥吹?,它就是為排序功能準(zhǔn)備的。

      PartialOrd被定義為 PartialEq的subtrait。它們?cè)陬愋蜕峡梢杂眠^程宏一起derive實(shí)現(xiàn)。

      #[derive(PartialEq, PartialOrd)]
      struct Point {
          x: i32,
          y: i32,
      }
      
      #[derive(PartialEq, PartialOrd)]
      enum Stoplight {
          Red,
          Yellow,
          Green,
      }
      

      8.5 Clone

      這個(gè)trait給目標(biāo)類型提供了clone()方法用來完整地克隆實(shí)例。

      #[stable(feature = "rust1", since = "1.0.0")]
      #[lang = "clone"]
      #[rustc_diagnostic_item = "Clone"]
      #[rustc_trivial_field_reads]
      pub trait Clone: Sized {
          /// Returns a copy of the value.
          ///
          /// # Examples
          ///
          /// ```
          /// # #![allow(noop_method_call)]
          /// let hello = "Hello"; // &str implements Clone
          ///
          /// assert_eq!("Hello", hello.clone());
          /// ```
          #[stable(feature = "rust1", since = "1.0.0")]
          #[must_use = "cloning is often expensive and is not expected to have side effects"]
          // Clone::clone is special because the compiler generates MIR to implement it for some types.
          // See InstanceKind::CloneShim.
          #[lang = "clone_fn"]
          fn clone(&self) -> Self;
      
          /// Performs copy-assignment from `source`.
          ///
          /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality,
          /// but can be overridden to reuse the resources of `a` to avoid unnecessary
          /// allocations.
          #[inline]
          #[stable(feature = "rust1", since = "1.0.0")]
          fn clone_from(&mut self, source: &Self) {
              *self = source.clone()
          }
      }
      

      通過方法的簽名,可以看到方法使用的是實(shí)例的不可變引用。

      fn clone(&self) -> Self;
      

      比如:

      #[derive(Clone)]
      struct Point {
          x: u32,
          y: u32,
      }
      

      因?yàn)槊恳粋€(gè)字段(u32類型)都實(shí)現(xiàn)了Clone,所以通過derive,自動(dòng)為Point類型實(shí)現(xiàn)了Clone trait。實(shí)現(xiàn)后,Point的實(shí)例 point 使用 point.clone() 就可以把自己克隆一份了。

      注意:clone() 是對(duì)象的深度拷貝,可能會(huì)有比較大的額外負(fù)載,但是就大多數(shù)情況來說其實(shí)還好。不要擔(dān)心在Rust中使用clone(),先把程序功能跑通最重要。Rust的代碼,性能一般都不會(huì)太差,畢竟起點(diǎn)很高。

      8.6 Copy

      #[rustc_unsafe_specialization_marker]
      #[rustc_diagnostic_item = "Copy"]
      pub trait Copy: Clone {
          // Empty.
      }
      

      定義為Clone的subtrait,并且不包含任何內(nèi)容,僅僅是一個(gè)標(biāo)記(marker)。

      Rust標(biāo)準(zhǔn)庫提供了Copy過程宏,可以讓我們自動(dòng)為目標(biāo)類型實(shí)現(xiàn)Copy trait。

      8.7 ToOwned

      ToOwned相當(dāng)于是Clone更寬泛的版本。ToOwned給類型提供了一個(gè) to_owned() 方法,可以將引用轉(zhuǎn)換為所有權(quán)實(shí)例。

      let a: &str = "123456";
      let s: String = a.to_owned();
      

      8.8 Drop

      Drop trait用于給類型做自定義垃圾清理(回收)。

      trait Drop {
          fn drop(&mut self);
      }
      

      實(shí)現(xiàn)了這個(gè)trait的類型的實(shí)例在走出作用域的時(shí)候,觸發(fā)調(diào)用drop()方法,這個(gè)調(diào)用發(fā)生在這個(gè)實(shí)例被銷毀之前。

      #[derive(PartialEq, Debug, Clone)]    // 注意這一句
      struct Point {
          x: i32,
          y: i32,
      }
      
      impl Drop for Point {
          fn drop(&mut self) {
              println!("Dropping point ({},{})",self.x,self.y);
          }
      }
      fn main() {
          let p = Point { x: 1, y: 2 };
          println!("{:?}", p);
      }
      

      輸出結(jié)果:

      一般來說,我們不需要為自己的類型實(shí)現(xiàn)這個(gè)trait,除非遇到特殊情況,比如我們要調(diào)用外部的C庫函數(shù),然后在C那邊分配了資源,由C庫里的函數(shù)負(fù)責(zé)釋放,這個(gè)時(shí)候我們就要在Rust的包裝類型(對(duì)C庫中類型的包裝)上實(shí)現(xiàn)Drop,并調(diào)用那個(gè)C庫中釋放資源的函數(shù)。

      8.9 From<T>Into<T>

      這兩個(gè) trait 用于類型轉(zhuǎn)換。

      From<T> 可以把類型T轉(zhuǎn)為自己,而 Into<T> 可以把自己轉(zhuǎn)為類型T。

      trait From<T> {
          fn from(T) -> Self;
      }
      trait Into<T> {
          fn into(self) -> T;
      }
      

      可以看到它們是互逆的trait。實(shí)際上,Rust只允許我們實(shí)現(xiàn) From<T>,因?yàn)閷?shí)現(xiàn)了From后,自動(dòng)就實(shí)現(xiàn)了Into,請(qǐng)看標(biāo)準(zhǔn)庫里的這個(gè)實(shí)現(xiàn)。

      impl<T, U> Into<U> for T
      where
          U: From<T>,
      {
          fn into(self) -> U {
              U::from(self)
          }
      }
      

      8.10 TryFrom TryInto

      TryFrom<T>TryInto<T>From<T>Into<T> 的可失敗版本。如果你認(rèn)為轉(zhuǎn)換可能會(huì)出現(xiàn)失敗的情況,就選擇這兩個(gè)trait來實(shí)現(xiàn)。

      trait TryFrom<T> {
          type Error;
          fn try_from(value: T) -> Result<Self, Self::Error>;
      }
      
      trait TryInto<T> {
          type Error;
          fn try_into(self) -> Result<T, Self::Error>;
      }
      

      可以看到,調(diào)用 try_from()try_into() 后返回的是Result,你需要對(duì)Result進(jìn)行處理。

      8.11 FromStr

      從字符串類型轉(zhuǎn)換到自身。

      trait FromStr {
          type Err;
          fn from_str(s: &str) -> Result<Self, Self::Err>;
      }
      

      比如字符串的 parse() 方法:

      use std::str::FromStr;
      
      fn example<T: FromStr>(s: &str) {
          // 下面4種表達(dá)等價(jià)
          let t: Result<T, _> = FromStr::from_str(s);
          let t = T::from_str(s);
          let t: Result<T, _> = s.parse();
          let t = s.parse::<T>(); // 最常用的寫法
      }
      

      8.12 as_ref

      trait AsRef<T> {
          fn as_ref(&self) -> &T;
      }
      

      它把自身的引用轉(zhuǎn)換成目標(biāo)類型的引用。和Deref的區(qū)別是, deref() 是隱式調(diào)用的,而 as_ref() 需要你顯式地調(diào)用。所以代碼會(huì)更清晰,出錯(cuò)的機(jī)會(huì)也會(huì)更少。

      AsRef<T> 可以讓函數(shù)參數(shù)中傳入的類型更加多樣化,不管是引用類型還是具有所有權(quán)的類型,都可以傳遞。比如;

      // 使用 &str 作為參數(shù)可以接收下面兩種類型
      //  - &str
      //  - &String
      fn takes_str(s: &str) {
          // use &str
      }
      // 使用 AsRef<str> 作為參數(shù)可以接受下面三種類型
      //  - &str
      //  - &String
      //  - String
      fn takes_asref_str<S: AsRef<str>>(s: S) {
          let s: &str = s.as_ref();
          // use &str
      }
      fn example(slice: &str, borrow: &String, owned: String) {
          takes_str(slice);
          takes_str(borrow);
          takes_str(owned); // ?
          takes_asref_str(slice);
          takes_asref_str(borrow);
          takes_asref_str(owned); // ?
      }
      

      在這個(gè)例子里,具有所有權(quán)的String字符串也可以直接傳入?yún)?shù)中了,相對(duì)于 &str 的參數(shù)類型表達(dá)更加擴(kuò)展了一步。

      你可以把 Deref 看成是隱式化(或自動(dòng)化)+弱化版本的 AsRef<T>

      posted @ 2025-08-26 18:30  Rust技術(shù)指南  閱讀(303)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 无码一区二区三区av在线播放| 性xxxx视频播放免费| 四虎亚洲国产成人久久精品| 中文字幕乱码中文乱码毛片 | 视频免费完整版在线播放| 久久中文字幕一区二区| 九九热视频在线精品18| 国产精品免费视频不卡| 免费现黄频在线观看国产| 一个色综合国产色综合| 日本在线视频网站www色下载 | 男人j进入女人j内部免费网站| 亚洲精品一区二区三区蜜臀| 我和亲妺妺乱的性视频| 久久国内精品一国内精品| 山西省| 久久午夜无码鲁丝片直播午夜精品 | 午夜性色一区二区三区不卡视频| 亚洲成a人片在线观看中| 狠狠五月深爱婷婷网| 国产精品十八禁在线观看| 伊人久久精品无码二区麻豆| 日本道之久夂综合久久爱| 国产精品入口中文字幕| 精品亚洲国产成人av| 无码一级视频在线| 99久久久国产精品消防器材| 丝袜老师办公室里做好紧好爽| 日日碰狠狠躁久久躁综合小说| 日本韩国日韩少妇熟女少妇| 国产成人毛片无码视频软件| 亚洲 制服 丝袜 无码| 亚洲天堂网中文在线资源| 看全黄大色黄大片视频| 99在线视频免费观看| 免费萌白酱国产一区二区三区 | 亚洲人成人日韩中文字幕| 日韩精品国产二区三区| 熟妇人妻不卡中文字幕| 国产av黄色一区二区三区| 亚洲丰满熟女一区二区v|