网站注册怎么做屏蔽过滤,微商官网,群晖可以做几个网站,榆林市城乡建设规划局网站本期看点#xff1a; 正文开始#xff1a;
切片的长度和容量
在Go语言中#xff0c;切片#xff08;slice#xff09;是一个引用类型#xff0c;它是对底层数组的抽象表示#xff0c;提供了动态长度的、灵活的序列类型。切片包含三个重要的属性#xff1a;指向底层数…本期看点 正文开始
切片的长度和容量
在Go语言中切片slice是一个引用类型它是对底层数组的抽象表示提供了动态长度的、灵活的序列类型。切片包含三个重要的属性指向底层数组的指针、切片的长度以及切片的容量。
长度Length 切片的长度是指切片中当前包含的元素个数。它可以通过内置的len()函数来获取。例如对于切片s其长度可以通过len(s)得到。容量Capacity 切片的容量是指从切片的第一个元素开始到底层数组中最后一个元素之间的元素个数。换句话说容量表示在不重新分配底层数组的情况下切片可以容纳的元素的最大数量。容量可以通过内置的cap()函数来获取。对于切片s其容量可以通过cap(s)得到。
切片的长度和容量之间有一个重要的关系切片的长度不会超过其容量。 这意味着当你尝试向切片添加更多元素时如果添加后的元素个数超过了切片的容量Go语言会创建一个新的、更大的底层数组并将原有元素和新元素复制到新数组中然后让切片指向这个新的底层数组。这个过程称为切片的扩容。
需要注意的是切片的长度和容量是可以变化的。当你使用append()函数向切片添加元素时如果添加后的元素个数没有超过容量那么切片的长度会增加但容量保持不变。如果超过了容量则会发生扩容切片的长度和容量都会增加。
一个简单的例子
func SliceLenAndCap1() {list : make([]int, 0)fmt.Printf(list elements %v , len %d , cap %d \n, list, len(list), cap(list))newList : append(list, 1, 2, 3)fmt.Printf(list elements %v , len %d , cap %d \n, newList, len(newList), cap(newList))newList2 : append(newList, 4)fmt.Printf(list elements %v , len %d , cap %d \n, newList2, len(newList2), cap(newList2))// 输出//list elements [] , len 0 , cap 0//list elements [1 2 3] , len 3 , cap 3//list elements [1 2 3 4] , len 4 , cap 6
}func SliceLenAndCap2() {list : []int{1, 2, 3}fmt.Printf(list elements %v , len %d , cap %d \n, list, len(list), cap(list))newList : append(list, 4)fmt.Printf(list elements %v , len %d , cap %d \n, newList, len(newList), cap(newList))// 输出//list elements [1 2 3] , len 3 , cap 3//list elements [1 2 3 4] , len 4 , cap 6
}在Go语言的源码src/runtime/slice.go中有growslice这样一个函数解释了切片的扩容原理当原切片长度小于 1024 时新的切片长度直接加上 append 元素的个数容量则会直接 *2当原切片长度大于等于 1024 时新的切片长度直接加上 append 元素的个数容量则会增加 1/4所以在日常开发中如果能明确知道切片的长度或者容量时我们需要在初始化的时候声明避免切片频繁扩容而带来的花销。
for循环中使用defer
在Go语言中defer语句用于在函数返回前执行一些清理操作无论函数是正常返回还是发生了panic。当你在for循环中使用defer时有几个关键点需要注意
延迟执行defer语句中的函数会在包含它的函数返回前被调用而不是在defer语句被执行时立即调用。这意味着如果你在for循环中使用了defer循环体内的代码会先执行完毕然后才会执行defer中的函数。后进先出LIFO 多个defer语句在函数中的执行顺序是后进先出。也就是说最后一个defer语句中的函数会第一个被调用依此类推。参数值当defer语句被遇到时会记录其函数和参数但参数的值是在defer实际执行时才被计算的。这意味着如果defer语句中的函数参数依赖于循环变量那么这些参数将使用循环结束时的值。
下面是一个例子来演示这些概念
package mainimport fmtfunc main() {for i : 0; i 5; i {defer fmt.Println(i)}
}在上面的代码中defer fmt.Println(i)语句会在每次循环迭代时都被记录但fmt.Println(i)函数本身并不会立即执行。当main函数返回时这些defer语句会按照后进先出的顺序执行。因为循环变量i在每次迭代时都被更新所以最终所有的defer语句都会打印出循环结束时的值即4。
如果你希望每个defer打印出它自己被创建时的循环变量值你可以通过将循环变量作为参数传递给一个匿名函数来捕获其当前值
package mainimport fmtfunc main() {for i : 0; i 5; i {defer func(x int) {fmt.Println(x)}(i)}
}在这个修改后的例子中我们创建了一个匿名函数它接受一个参数x并立即使用循环变量i的值来调用它。这样做可以确保每个defer语句捕获并记住它自己的i值并在稍后打印出来。输出将会是
4
3
2
1
0这展示了defer语句在for循环中是如何按照后进先出的顺序执行的并且说明了如何捕获循环变量的当前值以便在defer语句执行时使用。
Go语言TrimLeft函数
在Go语言的strings包中TrimLeft函数用于删除字符串左侧的指定字符集合。它接受两个参数一个是要处理的字符串另一个是要删除的字符集合。
下面是strings.TrimLeft的基本用法
package mainimport (fmtstrings
)func main() {str : Hello, World! // 去除字符串左侧的空格trimmed : strings.TrimLeft(str, )fmt.Println(trimmed) // 输出: Hello, World! // 去除字符串左侧的多个特定字符strWithPrefix : !!!Hello, World!!!trimmedWithPrefix : strings.TrimLeft(strWithPrefix, !)fmt.Println(trimmedWithPrefix) // 输出: Hello, World!!!// 去除字符串左侧的字符集合中的任意字符strWithChars : abcHello, World!abctrimmedWithChars : strings.TrimLeft(strWithChars, abc)fmt.Println(trimmedWithChars) // 输出: Hello, World!abc
}在上面的例子中我们首先使用strings.TrimLeft来删除字符串左侧的空格。然后我们删除了一个字符串左侧的多个感叹号字符。最后我们删除了一个字符串左侧的任何a、b或c字符。
需要注意的是strings.TrimLeft只删除字符串左侧的字符而不会对字符串的右侧进行任何操作。如果你想要同时删除字符串两侧的字符可以使用strings.TrimSpace仅删除空格或strings.Trim删除两侧的指定字符集合。
另外如果你想要删除字符串左侧满足某个条件的字符例如删除所有数字你可以使用正则表达式配合regexp包来实现但strings.TrimLeft本身只支持删除指定的字符集合。