在Rust中匹配字符串

24

我对Rust(1.31)还很陌生,想了解一个简单的代码片段,但它无法编译:

fn main() {
    s = String::from("foo");
    match s {
        "foo" => {
            println!("Yes");
        }
        _ => {
            println!("No");
        }
    }
}

相关的错误是:

10 |         "foo" => {                                                                                 
   |         ^^^^^ expected struct `std::string::String`, found reference

在这个错误之后,我决定将代码更改为:

fn main() {
    let s = String::from("foo");

    match s {
        String::from("foo") => {
            println!("Yes");
        }
        _ => {
            println!("No");
        }
    }
}

这样做的目的是为了得到正确的类型,但事实并非如此:

10 |         String::from("foo") => {                                                                   
   |         ^^^^^^^^^^^^^^^^^^^ not a tuple variant or struct

我对编译器的这条消息感到困惑,最终我通过实施以下操作使其正常工作:

fn main() {
    let s = String::from("foo");

    match &s as &str {
        "foo" => {
            println!("Yes");
        }
        _ => {
            println!("No");
        }
    }
}

然而,我不理解使这个解决方案正确的基本机制,以及为什么我的第二个例子不起作用。


匹配模式的左侧是一个模式。它不能包含函数调用(例如 String::from)。字面量 "foo" 是一个模式。 - Peter Hall
最后一次尝试成功的原因是因为String解引用为str。也就是说,String实现了Deref特质,并将str作为其输出类型。 - Peter Hall
1个回答

30

第一个示例不起作用,因为sString类型,这是一种拥有其中数据的字符串变体。它与字符串字面值(可以用作&str类型)匹配。match不知道如何比较这两种不同的类型,所以会出错。

然而,String通过实现Deref<Target=str>来解引用为&str,这意味着可以将对String的引用用于需要&str的地方,例如用于将其与之比较。这就是第三个示例中发生的情况。通过创建引用&s,可以进行隐式解引用,从而使这两种类型可比较。

您可以通过使用显式方法来从String创建&str来以稍微少一点魔力实现相同的效果:

fn main() {
    let s = String::from("foo");

    match s.as_str() {
        "foo" => {
            println!("Yes");
         },
         _ => {
             println!("No");
         }
    }
}
第二个例子试图使用String作为公共类型,使事情可比较,而不是&str。它无法工作,因为匹配期望左侧是模式,而不是创建新结构体的函数调用(这也会在后台分配内存)。即使它可以工作(例如将String的创建移动到匹配之外),这种方法也不太理想,因为新的String将需要进行内存分配。

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