【问题标题】:How do I concatenate strings?如何连接字符串?
【发布时间】:2015-07-21 04:22:47
【问题描述】:

如何连接以下类型组合:

  • strstr
  • Stringstr
  • StringString

【问题讨论】:

  • 请注意,str&str不同的类型,在 99% 的情况下,您应该只关心 &str。还有其他问题详细说明了它们之间的区别。
  • 这能回答你的问题吗? How to concatenate static strings in Rust

标签: string rust string-concatenation


【解决方案1】:

连接字符串时,需要分配内存来存储结果。最容易上手的是String&str

fn main() {
    let mut owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";
    
    owned_string.push_str(borrowed_string);
    println!("{}", owned_string);
}

在这里,我们有一个可以变异的自有字符串。这是有效的,因为它可能允许我们重用内存分配。 StringString 也有类似的情况,如 &String can be dereferenced as &str

fn main() {
    let mut owned_string: String = "hello ".to_owned();
    let another_owned_string: String = "world".to_owned();
    
    owned_string.push_str(&another_owned_string);
    println!("{}", owned_string);
}

在此之后,another_owned_string 保持不变(注意没有 mut 限定符)。还有另一个变体使用String,但不要求它是可变的。这是一个implementation of the Add trait,左侧为String,右侧为&str

fn main() {
    let owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";
    
    let new_owned_string = owned_string + borrowed_string;
    println!("{}", new_owned_string);
}

请注意,在调用 + 后,owned_string 将无法再访问。

如果我们想产生一个新的字符串,同时保持不变呢?最简单的方法是使用format!

fn main() {
    let borrowed_string: &str = "hello ";
    let another_borrowed_string: &str = "world";
    
    let together = format!("{}{}", borrowed_string, another_borrowed_string);

    // After https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html
    // let together = format!("{borrowed_string}{another_borrowed_string}");

    println!("{}", together);
}

请注意,两个输入变量都是不可变的,因此我们知道它们不会被触及。如果我们想对String 的任意组合做同样的事情,我们可以使用String 也可以被格式化的事实:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let another_owned_string: String = "world".to_owned();
    
    let together = format!("{}{}", owned_string, another_owned_string);

    // After https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html
    // let together = format!("{owned_string}{another_owned_string}");
    println!("{}", together);
}

你没有使用format!。您可以clone one string 并将另一个字符串附加到新字符串:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";
    
    let together = owned_string.clone() + borrowed_string;
    println!("{}", together);
}

注意 - 我所做的所有类型规范都是多余的 - 编译器可以在这里推断出所有类型。我添加它们只是为了让刚接触 Rust 的人清楚,因为我希望这个问题会受到该群体的欢迎!

【讨论】:

  • 你觉得Add / + 符号怎么样?如果你愿意,你可以覆盖它。
  • 也许这很简单,但理解它需要查看 Add with String 的可能类型签名。
  • 谢谢!您是否能够更深入地了解如何将 &String 取消引用为 &str?其实施的哪一部分允许这样做和/或它在文档中的什么地方这么说?
  • @jsalter 这是一个非常独立的主题,因此作为另一个顶级问题可能会很好。我已更新以链接到适当的文档(至少我能得到的尽可能接近...)
  • @ChrisMorgan 应该注意的是,由于 impl 专业化,自上述评论以来,.to_owned().to_string() 的差异已得到修复。现在,它们在&str 上调用时具有相同的性能。相关提交:github.com/rust-lang/rust/pull/32586/files
【解决方案2】:

要将多个字符串连接成一个字符串,由另一个字符分隔,有几种方法。

我见过的最好的方法是在数组上使用join 方法:

fn main() {
    let a = "Hello";
    let b = "world";
    let result = [a, b].join("\n");

    print!("{}", result);
}

根据您的用例,您可能还希望获得更多控制:

fn main() {
    let a = "Hello";
    let b = "world";
    let result = format!("{}\n{}", a, b);

    print!("{}", result);
}

我见过更多的手动方法,有些方法可以避免在这里和那里进行一两次分配。出于可读性的目的,我发现以上两个就足够了。

【讨论】:

  • join 记录在哪里?它似乎位于数组和字符串之间。我搜索了array 文档,很快就被搞糊涂了。
  • @DuaneJ join 实际上附加到the SliceContactExt trait。该特征被标记为不稳定,但它的方法是稳定的,are included in the Prelude 所以默认情况下它们可以在任何地方使用。团队似乎很清楚这个特性不需要存在,我想未来事情会随着它而改变。
  • 也许你应该提到joins1.to_owned().push_str(s2) 更有效地连接两个str,因为它避免了第二次分配。
【解决方案3】:

在 Rust 中连接字符串的简单方法

Rust 中有多种方法可以连接字符串

第一种方法(使用concat!()):

fn main() {
    println!("{}", concat!("a", "b"))
}

以上代码的输出是:

ab


第二种方法(使用push_str()+运算符):

fn main() {
    let mut _a = "a".to_string();
    let _b = "b".to_string();
    let _c = "c".to_string();

    _a.push_str(&_b);

    println!("{}", _a);

    println!("{}", _a + &_c);
}

以上代码的输出为:

ab

abc


第三种方法(Using format!()):

fn main() {
    let mut _a = "a".to_string();
    let _b = "b".to_string();
    let _c = format!("{}{}", _a, _b);

    println!("{}", _c);
}

以上代码的输出是:

ab

查看并试用Rust playground

【讨论】:

  • 此答案不会为现有答案添加任何新内容。
  • 答案的格式很好,这是有目的的。它可能不会添加任何新内容,但我很高兴@ashwin-rajeev 将其归结为。
【解决方案4】:

我认为concat方法和+也应该在这里提及:

assert_eq!(
  ("My".to_owned() + " " + "string"),
  ["My", " ", "string"].concat()
);

还有concat! 宏,但仅适用于文字:

let s = concat!("test", 10, 'b', true);
assert_eq!(s, "test10btrue");

【讨论】:

  • + 已在 existing answer 中提及。 (这是Add trait 的实现,它将String 作为左侧,&str 作为右侧:
  • 是的,现有答案太宽泛了,我没注意到。
  • 迄今为止的最佳答案。只需对字符串使用数组方法或 concat 即可。宏只是方便隐藏一些语法,而不是发明复杂的语法,使核心语言变得晦涩难懂。添加 trait 对对象来说可能很好,但至少会让人困惑。
【解决方案5】:

通过字符串插值连接

2019 年 10 月 27 日发布的 RFC 2795: 建议支持隐式参数来执行许多人所知的“字符串插值”——一种在字符串中嵌入参数以连接它们的方法。

RFC:https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html

最新的问题状态可以在这里找到: https://github.com/rust-lang/rust/issues/67984

在撰写本文时(2020 年 9 月 24 日),我相信这个功能应该在 Rust Nightly 版本中可用。

这将允许您通过以下速记进行连接:

format_args!("hello {person}")

相当于这样:

format_args!("hello {person}", person=person)

还有 "ifmt" crate,它提供了自己的字符串插值:

https://crates.io/crates/ifmt

【讨论】:

  • 现在这在 Rust 1.58 Beta 中可用。
【解决方案6】:

默认情况下,Rust 中的所有内容都是关于 MemoryManage、Owenership 和 Move,因此我们通常看不到复制或深复制 如果您尝试连接字符串,那么左侧应该输入可增长且应该是可变类型的字符串,而右侧可以是普通字符串文字,也就是类型字符串切片

    fn main (){
            let mut x = String::from("Hello"); // type String
            let y = "World" // type &str
            println!("data printing -------> {}",x+y);



}

来自 doc 的官方声明,这是指您尝试使用 arthmatic + 运算符时

【讨论】:

    猜你喜欢
    • 2011-02-12
    • 2012-01-15
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2012-01-02
    • 2011-11-04
    相关资源
    最近更新 更多