眼看着你们堕落 發表於 2025-5-20 09:18:00

rust进阶-基础.2.Option类型

<p>Option类型是Rust中非常重要的一个类型,和Result也类似。</p>
<p>本文主要根据文档:枚举类型Option编写</p>
<p>主要阐述以下内容:</p>
<p>1.Option和Result比较</p>
<p>2.Option的主要方法</p>
<p>3.示例</p>
<p>&nbsp;</p>
<h1>1.Option和Result比较</h1>
<p>以下内容来自于文心一言</p>
<table class="OxEWNITQ">
<thead>
<tr>
<th><strong>特性</strong></th>
<th><strong>Option</strong></th>
<th><strong>Result</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>目的</strong></td>
<td>表示一个值可能存在(<code class=" inline">Some(T)</code>)或不存在(<code class=" inline">None</code>),避免空指针异常。</td>
<td>表示一个操作可能成功(<code class=" inline">Ok(T)</code>)或失败(<code class=" inline">Err(E)</code>),需携带错误信息。</td>
</tr>
<tr>
<td><strong>典型场景</strong></td>
<td>集合查找(如<code class=" inline">Vec::get</code>)、可选字段(如链表节点的<code class=" inline">next</code>指针)。</td>
<td>文件I/O、网络请求、解析验证(如JSON反序列化)。</td>
</tr>
<tr>
<td><strong>错误处理</strong></td>
<td>仅表示值的存在性,无法传递错误上下文(如<code class=" inline">None</code>无法区分“未找到”与“空输入”)。</td>
<td>通过<code class=" inline">Err(E)</code>携带错误类型,支持精细化错误处理(如区分“文件不存在”与“权限不足”)。</td>
</tr>
</tbody>
</table>
<p>这些应该是主要的差异。</p>
<p>Result可以传递错误信息。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1>2.Option的主要方法</h1>
<p>&nbsp;</p>
<p><img src="https://img2024.cnblogs.com/blog/1177268/202505/1177268-20250519191812585-1079060593.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1>3.示例</h1>
<pre class="highlighter-prismjs language-rust prismjs-lines-highlighted" tabindex="0"><code>use std::iter::Sum;
#
struct Area {
    width: u32,
    height: u32,
    flag: bool,
}

impl Default for Area {
    fn default() -&gt; Self {
      Area {
            width: 103,
            height: 2012,
            flag: true,
      }
    }
}
impl Iterator for Area {
    type Item = u32;

    fn next(&amp;mut self) -&gt; Option&lt;Self::Item&gt; {
      if self.flag {
            let area = self.width * self.height;
            self.flag = false;
            Some(area)
      } else {
            None
      }
    }
}
/**
* 实现这个以便直接比较两个Area对象的大小,因为Rust不允许直接对结构体进行比较
*/
impl PartialEq for Area {
    fn eq(&amp;self, other: &amp;Self) -&gt; bool {
      let self_area = self.width * self.height;
      let other_area = other.width * other.height;
      self_area == other_area
    }
}
/**
* 实现这个以便直接比较两个Area对象的大小,因为Rust不允许直接对结构体进行比较
*/
impl PartialOrd for Area {
    fn partial_cmp(&amp;self, other: &amp;Self) -&gt; Option&lt;std::cmp::Ordering&gt; {
      let self_area = self.width * self.height;
      let other_area = other.width * other.height;
      Some(self_area.cmp(&amp;other_area))
    }
}
impl Area {
    fn area(&amp;self) -&gt; u32 {
      self.width * self.height
    }
}

#
struct Exam{
    test_time:u32,
    score:u32,
}
impl Sum for Exam{
   fn sum&lt;I&gt;(iter: I) -&gt; Self
       where I: Iterator&lt;Item = Exam&gt;{
      let mut total=Exam{test_time:0,score:0};
      for x in iter{
            if total.test_time==0 {
                total.test_time = x.test_time;
            }            
            total.score += x.score;
      }
      total
}
}


fn main() {
    println!("\n-- 测试直接操作   \n");
    let _r = test_direct_add(Some(1), Some(2));
   

    //两个同种Option直接比较
    println!("\n-- 测试直接比较   \n");
    test_direct_compare();
   
    //
    println!("\n-- 测试抽取值相关的方法   \n");
    test_extract_value();

    println!("\n-- 测试修改相关的方法   \n");
    test_modify();

    println!("\n-- 测试操作相关的方法   \n");
    test_operate();

    println!("\n-- 测试查询   \n");
    let value = Some(String::from("健康饮食。66天养成一个习惯"));
    test_query(value);

    println!("\n-- 测试引用相关的方法   \n");
    test_ref();

    println!("\n-- 测试转换相关的方法   \n");
    test_transform();
   
}

/**
* 两个Option可以直接比较,如果二者都实现了PartialOrd(Ord也可以)
* 那么可以使用基本的比较运算符进行比较
*/
fntest_direct_compare(){
    println!("要求其中的T实现PartialOrd");
    let d=Area::default();
    let a=Area{width: 10, height:20, flag:true};
    if d&gt;a{
      println!("{:?}&gt;{:?}",d,a);
    }else{
      println!("{:?}&lt;={:?}",d,a);
    }
}

/**
* 直接使用?操作符,如果Option是Some则返回里面的值,如果是None则返回None。
*/
fn test_direct_add(a: Option&lt;i32&gt;, b: Option&lt;i32&gt;) -&gt; Option&lt;i32&gt; {
    let result=Some(a? + b?);
    println!("{}+{}={}",a.unwrap(),b.unwrap(), result.unwrap());
    result
}

/**
* 取值后,通常而言,原来的变量不可在引用
*/
fn test_extract_value() {
    //测试unwrap_or 和unwrap_or_else
    //unwrap_or_else 要求参数是一个FnOnce类型的匿名函数,且返回T类型值。

    let book = None;
    let book_name = book.unwrap_or("沈氏四声考".to_string()); //unwrap_or获取默认值
    println!("None unwrap_or后,值={}", book_name);
    let book = Some("沈氏四声考".to_string());
    let book1=Some("沈氏四声考".to_string());
    let book_name = book.unwrap_or_else(|| "沈氏四声考?".to_string()); //unwrap_or获取默认值
    println!("{:?}中的值通过unwrap_or_else={}", book1,book_name);

    //测试unwrap_or_default,此方法要求T类型实现Default trait,所以如果没有值情况下,返回的是该类型的默认值。
    let area: Option&lt;Area&gt; = None;
    let area_default = area.unwrap_or_default(); //获取默认值
    println!("Area是一个None,默认={:?}", area_default.area());

    //测试take,take_if,replace等方法。
    // take --take(&amp;mut self) -&gt; Option&lt;T&gt;,原来的变为None
    // take_if take_if&lt;P&gt;(&amp;mut self, predicate: P) -&gt; Option&lt;T&gt;。p:FnOnce(&amp;mut T) -&gt; bool
    //         在取的时候,可以对数据进行修改
    // replace replace(&amp;mut self, value: T) -&gt; Option&lt;T&gt;,替换原来的值,返回来源的值。关键是原来的保留,新的也存在.

    let mut a=Some(10);
    let ta=a.take(); //取出值,并把原来的值设置为None。
    println!("{:?}被取出后={:?}",ta, a);
    //take_if 要求参数是一个FnOnce类型的匿名函数,且返回bool类型值。
    let mut b=Some(20);
    let tb=b.take_if(|x| *x&gt;30);
    println!("{:?}被取出后={:?}",tb, b);
    //replace 要求参数是T类型值。
    let mut c=Some(30);
    let old=c.replace(40);
    println!("c={:?},old={:?}", c,old);

}

/**
* 测试如何修改一个Option内含值
*/
fn test_modify(){
   //方式有多种,已知的略。
   println!("演示insert,get_or_insert方法。");
   //此处介绍insert,get_or_insert方法。
   //insert(&amp;mut self, value: T) -&gt; &amp;mut T,会替换原来的值(如果有)
   //get_or_insert(&amp;mut self, value: T) -&gt; &amp;mut T , 如果没有值,则插入,否则取出已有的值。
   //不太明白这些方法有什么使用场景?

   let mut a=Some(10);
   let b=a.insert(20);
   *b+=10;
   println!("b={:?}", b);
   println!("a={:?}", a.unwrap());

   let mut a1=None;
   let c=a1.get_or_insert(30);
   println!("c={:?}", c);


}

fn test_operate(){
    //测试and - and只要有一个是None,则返回None,否则返回参数值
    //不知道这方法有何用? 就是用于测试两个Option?
    //除了and,还有or和xor。
    //or取其中一个值,如果有一个值是Some,则取之。如果变量本身是Some,则返回本身
    //xor和or基本一样,不同的是如果x.xor(y)中x,y都是Some,则返回None。

    let a = Some(10);
    let b:Option&lt;u32&gt; = None;
    let c=a.and(b);
    println!("c={:?}", c);

    //测试and_with
    let fx=|_|{Some(100)};
    let c=a.and_then(fx);
    println!("c={:?}", c);

}

fn test_query(value: Option&lt;String&gt;) {
    if value.is_some() {
      println!("{}", value.unwrap());
    } else {
      println!("没有值");
    }
}

/**
* rust可以象js那么随意,在函数中定义函数
*/
fn test_ref() {
    fn validate_type(val: Option&lt;&amp;String&gt;) {
      match val {
            Some(v) =&gt; println!("{}", *v),
            None =&gt; println!("没有值"),
      }
    }
    let a = Some(String::from("今君往死地,沉痛迫中肠"));
    let ref_a = &amp;a; // &amp;Option&lt;String&gt;
    let ref_a_ref = ref_a.as_ref(); //Option&lt;&amp;String&gt;
    validate_type(ref_a_ref);
}


fn test_transform() {
    let book: Option&lt;i32&gt; = None;
    let book_name = book.ok_or(-1);
    println!("{:?}", book_name);

    //测试无聊函数filter等。
    //filter函数要求T本身实现Iterator trait. struct转为迭代器本身就是很罕见的。
    let score = Some(10);
    let dd = score.filter(|x| *x &gt;= 10); // filter要求FnOnce的参数是&amp;T类型。
    println!("过滤后,{:?}", dd.unwrap());

    //测试map方法。
    //map返回Option&lt;U&gt;
    let area_default= Some(Area::default());
    println!("默认值={:?}", area_default);
    let area_new = area_default.map(|a| {
       a.area()
    });
    println!("area_new={:?}", area_new);

    //测试合并 x.zip(y)=Some((x,y)),如果其中一个为None则返回None。
    let rubbish=score.zip(area_new);
    println!("合并结果1={:?}", rubbish);
    let rubbish=book.zip(score);
    println!("合并结果2={:?}", rubbish);
    let rubbish=score.zip(book);
    println!("合并结果3={:?}", rubbish);

    //迭代行为,这是一种自动行为,不需要显式调用。
    let score:=;
    let score_vec:Vec&lt;u32&gt;=score.into_iter().chain(Some(90)).collect();
    println!("合并结果4(利用迭代器)={:?}", score_vec);
    //如果T实现了Sum,Product等trait,则可以调用sum,product等方法。 但是如果有一个成员为None,则返回None。
    let score1=Some(Exam{
      score:10,
      test_time:1994
    });
    let score2=Some(Exam{
      score:20,
      test_time:1994
    });
    let score_arr = ;
    let sum:Option&lt;Exam&gt;=score_arr.into_iter().sum();
    println!("总成绩={:?}", sum);
   
    //收集
    //收集Option还是有一些价值的.
    //注意:只要其中过一个是None,则返回None。

    let v: = ;
    let res: Option&lt;Vec&lt;u32&gt;&gt; = v.into_iter().collect();
    println!("通过collect收集的结果5(收集)={:?}", res.unwrap_or_default());
    //展示一个不是None的集合,返回的还是Option&lt;Vec&lt;T&gt;&gt;,所以需要unwrap一下。
    let v: = ;
    let res: Option&lt;Vec&lt;u32&gt;&gt; = v.into_iter().collect();
    println!("通过collect收集的结果5(收集)={:?}", res.unwrap());

}</code></pre>
<p>&nbsp;</p>
<p>输出示例:</p>
<p><img src="https://img2024.cnblogs.com/blog/1177268/202505/1177268-20250519191947731-751447724.png"></p>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:正在战斗中,转载请注明原文链接:https://www.cnblogs.com/lzfhope/p/18884761</p><br><br>
来源:https://www.cnblogs.com/lzfhope/p/18884761
頁: [1]
查看完整版本: rust进阶-基础.2.Option类型