Rust从入门到实战系列四十二:Slice 类型

commit a5e0c5b2c5f9054be3b961aea2c7edfeea591de8

slice 允许你引用集合中一段连续的元素序列,而不用引用整个集合。slice 是一类引用,所以它没有所有权。
这里有一个编程小习题:编写一个函数,该函数接收一个字符串,并返回在该字符串中找到的第一个单词。如果函数在该字符串中并未找到空格,则整个字符串就是一个单词,所以应该返回整个字符串。
让我们推敲下如何不用 slice 编写这个函数的签名,来理解 slice 能解决的问题:

first_word 函数有一个参数 &String。因为我们不需要所有权,所以这没有问题。不过应该返回什么呢?
我们并没有一个真正获取 部分字符串的办法。不过,我们可以返回单词结尾的索引,结尾由一个空格表示。试试如示例 4-7 中的代码。

let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return i;
}
}
s.len()
}
#
# fn main() {}

示例 4-7:first_word 函数返回 String 参数的一个字节索引值
因为需要逐个元素的检查 String 中的值是否为空格,需要用 as_bytes 方法将 String 转化为字节数组:

let bytes = s.as_bytes();
#
# for (i, &item) in bytes.iter().enumerate() {
# if item == b' ' {
# return i;
# }
# }
#
# s.len()
# }
#
# fn main() {}
接下来,使用 iter 方法在字节数组上创建一个迭代器:
# fn first_word(s: &String) -> usize {
# let bytes = s.as_bytes();
#
for (i, &item) in bytes.iter().enumerate() {
# if item == b' ' {
# return i;
# }
# }
#
# s.len()
# }
#
# fn main() {}

我们将在第十三章详细讨论迭代器。现在,只需知道 iter 方法返回集合中的每一个元素,而 enumerate包装了 iter 的结果,将这些元素作为元组的一部分来返回。enumerate 返回的元组中,第一个元素是索引,第二个元素是集合中元素的引用。这比我们自己计算索引要方便一些。
因为 enumerate 方法返回一个元组,我们可以使用模式来解构,我们将在第六章中进一步讨论有关模式的问题。所以在 for 循环中,我们指定了一个模式,其中元组中的 i 是索引而元组中的 &item 是单个字节。因为我们从 . iter (). enumerate() 中获取了集合元素的引用,所以模式中使用了 &。
在 for 循环中,我们通过字节的字面值语法来寻找代表空格的字节。如果找到了一个空格,返回它的位
置。否则,使用 s.len ()返回字符串的长度:

# let bytes = s.as_bytes();
#
# for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return i;
}
}
s.len()
# }
#
# fn main() {}

现在有了一个找到字符串中第一个单词结尾索引的方法,不过这有一个问题。我们返回了一个独立的usize,不过它只在 &String 的上下文中才是一个有意义的数字。换句话说,因为它是一个与 String 相分离的值,无法保证将来它仍然有效。考虑一下示例 4-8 中使用了示例 4-7 中 first_word 函数的程序。

# let bytes = s.as_bytes();
#
# for (i, &item) in bytes.iter().enumerate() {
# if item == b' ' {
# return i;
# }
# }
#
# s.len()
# }
#
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s); // word 的值为 5
s.clear(); // 这清空了字符串,使其等于 ""
// word 在此处的值仍然是 5,
// 但是没有更多的字符串让我们可以有效地应用数值 5。word 的值现在完全无效!
}

这个程序编译时没有任何错误,而且在调用 s.clear () 之后使用 word 也不会出错。因为 word 与 s 状态完全没有联系,所以 word 仍然包含值 5。可以尝试用值 5 来提取变量 s 的第一个单词,不过这是有bug 的,因为在我们将 5 保存到 word 之后 s 的内容已经改变。
我们不得不时刻担心 word 的索引与 s 中的数据不再同步,这很啰嗦且易出错!如果编写这么一个second_word 函数的话,管理索引这件事将更加容易出问题。它的签名看起来像这样:

现在我们要跟踪一个开始索引 和一个结尾索引,同时有了更多从数据的某个特定状态计算而来的值,但都完全没有与这个状态相关联。现在有三个飘忽不定的不相关变量需要保持同步。
幸运的是,Rust 为这个问题提供了一个解决方法:字符串 slice。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值