rust入坑之旅-Slice
slice
字符串的slice(string slice)是 String 中一部分值的引用,slice是没有capacity的。它看起来像这样:
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
hello
引用 s [0..5]的部分。它不是对整个 String 的引用,而是对部分 String 的引用。
编程题
返回给定字符串的第一个单词
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
所有权、借用和 slice 这些概念让 Rust 程序在编译时确保内存安全。Rust 语言提供了跟其他系统编程语言相同的方式来控制你使用的内存,但拥有数据所有者在离开作用域后自动清除其数据的功能意味着你无须额外编写和调试相关的控制代码
Golang Slice
与Rust的Slice相比,Go的slice的array是一个指针,指向一块连续内存。go的slice可以修改底层数组的内容,而Rust的Slice是没有对原始数据操作的所有权的。下面试golang slice的源码
type slice struct {
array unsafe.Pointer
len int
cap int
}
可以看到slice中定义了三个变量,一个是指向底层数字的指针array,另外两个是切片的长度len和切片的容量cap。Go的Slice扩容规则是,从1->2->4->8->16...->1024,都是成倍增长,当cap大于1024后,再append元素,cap变为1280,变成了1024的1.25倍,在rust中slice则是一个字符串或者是数组的部分值,而且也无法修改源数据,在golang则不是,那么在golang中Slice在作为函数参数进行传递的时候,是值传递还是引用传递!
func main() {
slice := make([]int, 0, 10)
slice = append(slice, 1)
fmt.Println(slice, len(slice), cap(slice))
fn(slice)
fmt.Println(slice, len(slice), cap(slice))
}
func fn(in []int) {
in = append(in, 5)
}
output :
[1] 1 10
[1] 1 10
在函数传递之后 fn函数捕捉到的是slice的一个副本,但是由于GoLang中的slice可以理解是底层数据的一个窗口而且对其的操作会影响底层数组,所以在第二个打印语句中发现了结果和fn函数执行之前一样,所以这个也反映了slice在函数传递是值传递,传递了一个副本,但是底层数组的的内容已经发生了改变。 底层数组已经是 1 5 0 0 0 0 0 0 0 0
,由于传递副本的缘由,那么这个5并没有展示的缘由本质是 slice的长度并没有改变所以,如果对slice的长度发生改变,这个5就会展示。所以这里如果在开发过程中处理不当,就会导致些奇奇怪怪的问题。