在知道了能够获取字面值和 String 的 slice 后,我们对 first_word 做了改进,这是它的签名:
而更有经验的 Rustacean 会编写出示例 4-9 中的签名,因为它使得可以对 String 值和 &str 值使用相同的函数:
# let bytes = s.as_bytes();
#
# for (i, &item) in bytes.iter().enumerate() {
# if item == b' ' {
# return &s[0..i];
# }
# }
#
# &s[..]
# }
#
# fn main() {
# let my_string = String::from("hello world");
#
# // `first_word` 适用于 `String`(的 slice),整体或全部
# let word = first_word(&my_string[0..6]);
# let word = first_word(&my_string[..]);
# // `first_word` 也适用于 `String` 的引用,
# // 这等价于整个 `String` 的 slice
# let word = first_word(&my_string);
#
# let my_string_literal = "hello world";
#
# // `first_word` 适用于字符串字面值,整体或全部
# let word = first_word(&my_string_literal[0..6]);
# let word = first_word(&my_string_literal[..]);
#
# // 因为字符串字面值已经 ** 是 ** 字符串 slice 了,
# // 这也是适用的,无需 slice 语法!
# let word = first_word(my_string_literal);
# }
如果有一个字符串 slice,可以直接传递它。如果有一个 String,则可以传递整个 String 的 slice 或对String 的引用。这种灵活性利用了 deref coercions 的优势,这个特性我们将在” 函数和方法的隐式 Deref强制转换” 章节中介绍。定义一个获取字符串 slice 而不是 String 引用的函数使得我们的 API 更加通用并且不会丢失任何功能:
# let bytes = s.as_bytes();
#
# for (i, &item) in bytes.iter().enumerate() {
# if item == b' ' {
# return &s[0..i];
# }
# }
#
# &s[..]
# }
#
fn main() {
let my_string = String::from("hello world");
// `first_word` 适用于 `String`(的 slice),整体或全部
let word = first_word(&my_string[0..6]);
let word = first_word(&my_string[..]);
// `first_word` 也适用于 `String` 的引用,
// 这等价于整个 `String` 的 slice
let word = first_word(&my_string);
let my_string_literal = "hello world";
// `first_word` 适用于字符串字面值,整体或全部
let word = first_word(&my_string_literal[0..6]);
let word = first_word(&my_string_literal[..]);
// 因为字符串字面值已经 ** 是 ** 字符串 slice 了,
// 这也是适用的,无需 slice 语法!
let word = first_word(my_string_literal);
}