如何在Arc内匹配Option?

6
Arc<T>的文档中写到:
"Arc<T>会自动通过Deref trait转换成T,因此可以在类型为Arc<T>的值上调用T的方法。"
但是有没有一种方法可以匹配Option类型呢?
下面是一个简单的例子:
use std::sync::Arc;

fn main() {
    let foo: Arc<Option<String>> = Arc::new(Some("hello".to_string()));

    if foo.is_some() {
        println!("{}", foo.unwrap());
    }

    match foo {
        Some(hello) => {
            println!("{}", hello);
        }
        None => {}
    }
}

编译器错误为:
error[E0308]: mismatched types
  --> src/main.rs:11:9
   |
11 |         Some(hello) => {
   |         ^^^^^^^^^^^ expected struct `std::sync::Arc`, found enum `std::option::Option`
   |
   = note: expected type `std::sync::Arc<std::option::Option<std::string::String>>`
              found type `std::option::Option<_>`

error[E0308]: mismatched types
  --> src/main.rs:14:9
   |
14 |         None => {}
   |         ^^^^ expected struct `std::sync::Arc`, found enum `std::option::Option`
   |
   = note: expected type `std::sync::Arc<std::option::Option<std::string::String>>`
              found type `std::option::Option<_>`
2个回答

12

不,你不能在Arc内部匹配Option。要在模式匹配中使用类型,必须可以访问该类型的实现,但Arc的实现不是公开的。


在某些情况下,您可以执行某种转换以匹配引用
例如,由于Arc<T>实现了Deref,因此您可以使用*运算符通过Arc<T>T进行取消引用。由于有某些人体工程学语法用于这种匹配,因此您可以在不拥有它的情况下获取Option内部值的引用:
match *foo {
    Some(ref hello) => {
        println!("{}", hello);
    }
    None => {}
}

你还可以使用Option :: as_ref&Option<T>(通过DerefArc<T>自动解引用)转换为Option<&T>

match Option::as_ref(&foo) {
    Some(hello) => {
        println!("{}", hello);
    }
    None => {}
}

很遗憾,你不能直接调用.as_ref(),因为trait方法AsRef::as_ref优先级更高。

在这两种情况下,如果你只关心匹配分支中的一个,使用if let更符合惯用法:

if let Some(ref hello) = *foo {
    println!("{}", hello);
}

3

第一个 println 在编译器的早期阶段已经通过了,但在后来的阶段被借用检查器标记为有问题。第二个 println 更容易修复。

use std::sync::Arc;

fn main() {
    let foo: Arc<Option<String>> = Arc::new(Some("hello".to_string()));

    if foo.is_some() {
        let f1: &Option<String> = foo.as_ref();
        let f2: Option<&String> = f1.as_ref();
        let f3: &String = f2.unwrap();
        println!("{}", f3);

        println!("{}", foo.as_ref().as_ref().unwrap())
    }

    match *foo {
        Some(ref hello) => {
            println!("{}", hello);
        }
        None => {}
    }
}

第一个println令人困惑地使用了两个as_ref()方法调用。第一个as_ref作用于Arc,类型签名为Fn(&Arc<Option<String>>) -> &Option<String>。第二个as_ref作用于Option,类型签名为Fn(&Option<String>) -> Option<&String> playground

2
解除引用 foo(例如 let f2 = (*foo).as_ref())比在 Arc 上使用 .as_ref 更符合惯用语。 - trent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接