当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Rust String用法及代码示例


本文简要介绍rust语言中 Struct alloc::string::String 的用法。

用法

pub struct String { /* fields omitted */ }

一个 UTF-8 编码的、可增长的字符串。

String 类型是最常见的字符串类型,它拥有对字符串内容的所有权。它与其借用的对应物原语 str 有着密切的关系。

例子

您可以使用 String::from a literal string 创建 String

let hello = String::from("Hello, world!");

您可以使用 push 方法将 char 附加到String,并使用 push_str 方法附加 &str

let mut hello = String::from("Hello, ");

hello.push('w');
hello.push_str("orld!");

如果你有一个 UTF-8 字节的向量,你可以使用 from_utf8 方法从它创建一个 String

// some bytes, in a vector
let sparkle_heart = vec![240, 159, 146, 150];

// We know these bytes are valid, so we'll use `unwrap()`.
let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();

assert_eq!("💖", sparkle_heart);

UTF-8

String 始终是有效的 UTF-8。这有一些含义,首先是如果您需要非 UTF-8 字符串,请考虑 OsString 。它类似,但没有 UTF-8 约束。第二个含义是您不能索引到 String

let s = "hello";

println!("The first letter of s is {}", s[0]); // ERROR!!!

索引旨在成为 constant-time 操作,但 UTF-8 编码不允许我们这样做。此外,还不清楚索引应该返回什么样的东西:一个字节、一个代码点或一个字形簇。 bytes chars 方法分别返回前两个的迭代器。

去参考

String 实现了 Deref<Target = str> ,因此继承了所有 str 的方法。此外,这意味着您可以通过使用与号 (&) 将 String 传递给采用 &str 的函数:

fn takes_str(s: &str) { }

let s = String::from("Hello");

takes_str(&s);

这将从 String 创建一个 &str 并将其传入。这种转换非常便宜,因此通常,函数将接受 &str 作为参数,除非它们出于某种特定原因需要 String

在某些情况下,Rust 没有足够的信息来进行这种转换,称为 Deref coercion。在下面的示例中,字符串切片 &'a str 实现了特征 TraitExample ,函数 example_func 采用任何实现特征的东西。在这种情况下,Rust 需要进行两次隐式转换,而 Rust 没有办法做到这一点。因此,以下示例将无法编译。

trait TraitExample {}

impl<'a> TraitExample for &'a str {}

fn example_func<A: TraitExample>(example_arg: A) {}

let example_string = String::from("example_string");
example_func(&example_string);

有两个选项可以代替。第一个是将行 example_func(&example_string); 更改为 example_func(example_string.as_str()); ,使用方法 as_str() 显式提取包含字符串的字符串切片。第二种方式将 example_func(&example_string); 更改为 example_func(&*example_string); 。在这种情况下,我们将 String 取消引用到 str ,然后将 str 引用回 &str 。第二种方式更惯用,但是两者都可以显式地进行转换,而不是依赖于隐式转换。

表示

String 由三个部分组成:指向某些字节的指针、长度和容量。指针指向一个内部缓冲区 String 用于存储其数据。长度是当前存储在缓冲区中的字节数,容量是缓冲区的大小(以字节为单位)。因此,长度将始终小于或等于容量。

此缓冲区始终存储在堆上。

您可以使用 as_ptr len capacity 方法查看这些:

use std::mem;

let story = String::from("Once upon a time...");

// Prevent automatically dropping the String's data
let mut story = mem::ManuallyDrop::new(story);

let ptr = story.as_mut_ptr();
let len = story.len();
let capacity = story.capacity();

// story has nineteen bytes
assert_eq!(19, len);

// We can re-build a String out of ptr, len, and capacity. This is all
// unsafe because we are responsible for making sure the components are
// valid:
let s = unsafe { String::from_raw_parts(ptr, len, capacity) } ;

assert_eq!(String::from("Once upon a time..."), s);

如果String 有足够的容量,向其中添加元素不会重新分配。例如,考虑这个程序:

let mut s = String::new();

println!("{}", s.capacity());

for _ in 0..5 {
    s.push_str("hello");
    println!("{}", s.capacity());
}

这将输出以下内容:

0
5
10
20
20
40

起初,我们根本没有分配内存,但是当我们追加到字符串时,它会适当地增加它的容量。如果我们改为使用 with_capacity 方法来分配正确的容量:

let mut s = String::with_capacity(25);

println!("{}", s.capacity());

for _ in 0..5 {
    s.push_str("hello");
    println!("{}", s.capacity());
}

我们最终得到不同的输出:

25
25
25
25
25
25

在这里,无需在循环内分配更多内存。

相关用法


注:本文由纯净天空筛选整理自rust-lang.org大神的英文原创作品 Struct alloc::string::String。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。