如何将一个字符串与字符串字面量进行匹配?

411

我正在尝试查找如何在Rust中匹配字符串String

最初我是这样匹配的,但我发现Rust无法将 std::string::String 隐式转换为 &str

fn main() {
    let stringthing = String::from("c");
    match stringthing {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
    }
}

这里出现了错误:

error[E0308]: mismatched types
 --> src/main.rs:4:9
  |
4 |         "a" => println!("0"),
  |         ^^^ expected struct `std::string::String`, found reference
  |
  = note: expected type `std::string::String`
             found type `&'static str`

因为找不到将String类型转换为&str类型的函数,所以我尝试构建新的String对象。

fn main() {
    let stringthing = String::from("c");
    match stringthing {
        String::from("a") => println!("0"),
        String::from("b") => println!("1"),
        String::from("c") => println!("2"),
    }
}

这让我连续出现了3次以下错误:

error[E0164]: `String::from` does not name a tuple variant or a tuple struct
 --> src/main.rs:4:9
  |
4 |         String::from("a") => return 0,
  |         ^^^^^^^^^^^^^^^^^ not a tuple variant or struct

如何在Rust中实际匹配String


8
stringthing.as_str() 可能是所有答案中最直接的;我不喜欢 as_ref,因为它过于泛化,可能会导致错误,并且不够明确,不完全清楚 as_ref() 将会是一个 &str,而 as_str 则更加简单易懂。 - Zorf
@Zorf 你说得对。当 as_str 还不存在时,答案已被接受。我改变了被接受的答案,但感谢所有回答这个问题的人! - Jeroen
9个回答

383

更新: 使用以下方式将 String 转换为 &str.as_str()

match stringthing.as_str() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

原因

.as_str()更加简洁并且强制实施更严格的类型检查。trait as_ref已经被多种类型实现,对于String 类型其行为可能会发生改变,导致意外的结果。同样,如果输入参数的类型发生变化,当该类型实现trait as_ref时编译器不会发出任何问题信号。

官方文档建议使用as_str,文档链接:https://doc.rust-lang.org/std/string/struct.String.html, https://doc.rust-lang.org/std/primitive.str.html

旧回答:

as_slice已经被弃用,你现在应该使用trait std::convert::AsRef代替:

match stringthing.as_ref() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

请注意,您还需要明确处理“catch-all”情况。


4
在使用 Rust 1.4.0 版本时,可以使用 trim() 函数。仅使用 as_ref() 无法匹配字符串。 - futtetennista
1
我认为匹配失败是因为trim()去除了空格。这对于解除引用以匹配用户输入非常有用。 - Gerard Sexton
2
它不起作用。只有当我从read_line获取字符串时,它才能匹配“_”。 - Masked Man
不太了解Rust如何管理不同类型的字符串,但是基本示例看起来可以正常工作 - tforgione
2
@MaskedMan read_line 读取一行。每行以 \n 结尾。.trim_end()(或者更精确地说,trim_end_matches('\n'))可以帮你去掉它。 - wizzwizz4
我完全不理解.as_str()。对于字符串参数"xx",它不被允许:"foo(xx: &str)"。然而,"match xx { "ABC" => "XYZ", ... }"却可以正常工作。这是一个借用实例/参数。如果使用as_str()是正确或更好的方法,那么它该如何运作? - will

192

你可以像这样做:

match &stringthing[..] {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

自Rust 1.7.0起,还引入了as_str方法:

match stringthing.as_str() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

25

1
这实际上与.as_str()相同,但更短。 - amyiris
5
“.as_str()”比“as &str”多一个字符,是我漏看了什么吗?@amyiris - Luis Octavio Lomeli Navarrete
2
&x as &str 是10个字符,而 x.as_str() 也是10个字符。长度相同。 - jcdyer

11

编辑备注:此答案适用于 Rust 1.0 之前的版本,在 Rust 1.0 中不起作用。

你可以匹配一个字符串切片。

match stringthing.as_slice() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

3
最好使用.as_ref()还是.as_str(),两者都不会获取所有权。 - Abrar Khan

3
您可以尝试以下方法:
fn main() {
    let stringthing = String::from("c");
    match &*stringthing {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
        _ => println!("else")
    }
}

12
如果您解释一下&*stringthing的意思和作用,可能会提高您回答的实用性。 - Seth Difley
String 实现了 Deref<Target = str>。因此,可以使用 *stringthingstringthing 解引用为 str,并使用 &*stringthing 引用为 &str。根据 Rust 文档,这比使用 as_str() 更符合惯用方式。 - Kaplan
1
这对于有强迫症的人来说很好,s.as_ref()s.as_str()看起来很丑陋,而&*s更好。 - Sunding Wei

2
你可以使用as_str()方法将String转换为&str,然后像这样匹配&str值:
fn main() {
    let stringthing = String::from("c");
    match stringthing.as_str() {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
        _ => println!("other"),
    }
}

或者您可以将字符串值绑定到变量上,然后像这样匹配变量:

fn main() {
    let stringthing = String::from("c");
    match stringthing {
        ref x if x == "a" => println!("0"),
        ref x if x == "b" => println!("1"),
        ref x if x == "c" => println!("2"),
        _ => println!("other"),
    }
}

或者您可以使用 == 运算符将 String 值与字符串字面量进行比较,如下所示:

fn main() {
    let stringthing = String::from("c");
    if stringthing == "a" {
        println!("0");
    } else if stringthing == "b" {
        println!("1");
    } else if stringthing == "c" {
        println!("2");
    } else {
        println!("other");
    }
}

1
你可以通过以下方式将 String 转换为 &str
fn main() {
    let stringthing = String::from("c");
    match &stringthing[..] {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
    }
}

0
在Rust中,通常不能直接在匹配语句中使用String,因为String是一种动态的、堆分配的数据类型,而匹配语句在编译时期期望的是具有已知和固定可能性集的值。
然而,你可以通过首先使用as_str()方法将String转换为&str,或者使用带有对String的引用的模式匹配,在匹配语句中使用String。
匹配期望详尽和已知的模式:匹配表达式要求你在编译时指定所有可能的模式。字符串字面量在编译时是已知的,所以你可以直接在匹配中使用它们。另一方面,String的内容在运行时确定并且可能变化,所以不能直接在匹配中使用它。

-2

使用 as_str() 方法来获取字符串切片

fn main() {
    let stringthing = String::from("c");
    match stringthing.as_str() {
        String::from("a") => println!("0"),
        String::from("b") => println!("1"),
        String::from("c") => println!("2"),
    }
}

如果您从控制台输入并想要对其执行匹配,请确保在 as_str() 后调用 trim() 以删除输入中的转义字符,即 '\n'。例如:

match stringthing.as_str().trim() {...}



3
这个不行。错误:期望元组结构体或元组变量,但发现了关联函数 String::fromhttps://play.rust-lang.org/?version=stable&mode=debug&edition=2021 - FreelanceConsultant

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