Rust 如何与选项进行模式匹配<;字符串>;?

Rust 如何与选项进行模式匹配<;字符串>;?,rust,pattern-matching,Rust,Pattern Matching,我可以直接在Rust中匹配字符串: let a = "hello".to_string(); match &a[..] { "hello" => { println!("Matches hello"); } _ => panic!(), } 如果我有一个选项类型,它将失败: match Some(a) { Some("hello") => { println!("Matches some hello")

我可以直接在Rust中匹配
字符串

let a = "hello".to_string();

match &a[..] {
    "hello" => {
        println!("Matches hello");
    }
    _ => panic!(),
}
如果我有一个选项类型,它将失败:

match Some(a) {
    Some("hello") => {
        println!("Matches some hello");
    }
    _ => panic!(),
}
因为类型不匹配:

错误[E0308]:类型不匹配
-->src/main.rs:5:14
|
5 |一些(“你好”)=>{
|^^^^应为结构'std::string::string',找到引用
|
=注意:应为'std::string::string'类型`
找到类型`&'static str`
我不能做
[…]
把戏,因为我们有一个
选项
到目前为止,我得出的结论是:

match Some(a) {
    Some(b) => match (&b[..]) {
        "hello" => {
            println!("Matches some, some hello");
        }
        _ => panic!(),
    },
    None => panic!(),
}
这是有效的,但它的冗长可怕

在本例中,我的代码只是一个示例。我既不能控制
字符串
的创建,也不能控制
某些(字符串)
的创建-因此,我不能像在示例中那样实际更改此类型

还有其他选择吗?

您无法在
std::String
上进行匹配,正如您所发现的,只能在
&str
上进行匹配。嵌套模式匹配有效,因此如果可以在
&str
上进行匹配,则可以在
选项上进行匹配,但仍然不能在
选项上进行匹配

在工作示例中,通过执行
&a[…]
,将
std::String
转换为
&str
。如果要匹配
选项,则必须执行相同的操作

一种方法是使用嵌套匹配:

match a {
    Some(ref s) => match &s[..] {
        "hello" => /* ... */,
        _ => /* ... */,
    },
    _ => /* ... */,
}
但是如果“否则”的代码是相同的,那么你就必须复制它,而这通常不是很好

相反,您可以使用
映射
函数将
选项
转换为
选项
并进行匹配。但是,
映射
会消耗调用它的值,将其移动到映射函数中。这是一个问题,因为您希望引用字符串,如果将其移动到mappi中,则无法执行此操作ng函数。首先需要将
选项
转换为
选项
,并映射到该选项上

因此,您最终得到了
a.as_ref().map(|s |/*s是type&String*/&s[…])
。然后您可以在这一点上进行匹配

match os.as_ref().map(|s| &s[..]) {
    Some("hello") => println!("It's 'hello'"),
    // Leave out this branch if you want to treat other strings and None the same.
    Some(_) => println!("It's some other string"),
    _ => println!("It's nothing"),
}

这是已知的锈迹模式的局限性

方法调用(包括运算符的内部方法,如
==
)会根据需要自动调用
.deref()
,因此
字符串
会自动转换为
&str
,以便与文本进行比较

另一方面,这些模式在比较中相当直白,并且发现
String
&str
是不同的

有两种解决方案:

  • 在匹配之前,将
    选项更改为
    选项:
    一些(a).as_deref()
    as_deref()
    as_ref()
    的组合,使
    选项(防止移动)和
    deref()
    /
    as_str()
    ,然后明确地将其引用为
    &str

  • 使用match-guard:
    match Some(a){Some(ref s)if s==“hello”=>…}
    Some(ref s)
    匹配任何
    String
    ,并将其捕获为
    s:&String
    ,然后可以在
    if
    保护中进行比较,该保护执行通常的灵活强制操作

  • 另见:


    在某些情况下,您可以使用
    unwrap\u或
    选项::None
    替换为预定义的
    &str
    ,您不希望以任何特殊方式进行处理

    我用它来处理用户输入:

    let args: Vec<String> = env::args().collect();
    
    match args.get(1).unwrap_or(&format!("_")).as_str() {
        "new" => {
            print!("new");
        }
        _ => {
            print!("unknown string");
        }
    };
    

    从Rust 1.40开始,您现在可以在
    选项
    上调用
    As_deref
    ,将其转换为
    选项
    ,然后在其上进行匹配:

    match args.nth(1).as_deref(){
    一些(“帮助”)=>{}
    一些(s)=>{}
    无=>{}
    }
    

    我发现这是因为它是。

    这很好——我更喜欢1,因为它不太详细,因为我想匹配多个字符串。但是,我发现它令人困惑。为什么我们可以在
    选项上对单个值创建迭代器
    ?为什么我们可以在
    映射
    返回时匹配单个值?这不是
    迭代器
    类型吗?这里的
    .map()
    根本不是迭代器。它是
    选项
    上的一个辅助方法,允许您在
    部分
    时更改它,如果
    则什么也不做。啊,请原谅我的无知。完全误解了rust doc的选项。是的,您是对的--“map”==使用与集合相同的名称将一个选项映射到另一个选项。点1的替代选项可以是
    Some(a)。as_deref()
    您可以通过更改引用/展开顺序来避免临时分配:
    选项。as_deref().unwrap_或(“未处理的字符串”)
    。也可以
    字符串::from(“\ux”)
    生成的代码远远少于动态格式化机制。
    let option = Some("hello");
    
    match option.unwrap_or(&format!("unhandled string").as_str()) {
        "hello" => {
            println!("hello");
        }
        _ => {
            println!("unknown string");
        }
    };