0
点赞
收藏
分享

微信扫一扫

go语言学习----字符串、数组和切片的应用



 字符串、数组和切片的应用

 从字符串生成字节切片

​c := []bytes(s)​​ 来获取一个字节的切片 c。另外,您还可以通过 copy 函数来达到相同的目的:​​copy(dst []byte, src string)​​。

同样的,还可以使用 for-range 来获得每个元素(Listing 7.13—for_string.go):


package main

import "fmt"

func main() {
s := "\u00ff\u754c"
for i, c := range s {
fmt.Printf("%d:%c ", i, c)
}
}


输出:


0:ÿ 2:界


​c := []int(s)​​ 语法,这样切片中的每个 int 都会包含对应的 Unicode 代码,因为字符串中的每次字符都会对应一个整数。类似的,您也可以将字符串转换为元素类型为 rune 的切片:​​r := []rune(s)​​。​​len([]int(s))​​ 来获得字符串中字符的数量,但使用 ​​utf8.RuneCountInString(s)​​ 效率会更高一点。(参考​​​count_characters.go​​)

您还可以将一个字符串追加到某一个字符数组的尾部:


var b []byte
var s string
b = append(b, s...)


 获取字符串的某一部分

​substr := str[start:end]​​ 可以从字符串 str 获取到从索引 start 开始到 ​​end-1​​ 位置的子字符串。同样的,​​str[start:]​​ 则表示获取从 start 开始到 ​​len(str)-1​​ 位置的子字符串。而 ​​str[:end]​​ 表示获取从 0 开始到 ​​end-1​​的子字符串。

字符串和切片的内存结构

在内存中,一个字符串实际上是一个双字结构,即一个指向实际数据的指针和记录字符串长度的整数(见图 7.4)。因为指针对用户来说是完全不可见,因此我们可以依旧把字符串看做是一个值类型,也就是一个字符数组。

​string s = "hello"​​ 和子字符串 ​​t = s[2:3]​

​​

go语言学习----字符串、数组和切片的应用_字符串

​​

 修改字符串中的某个字符

​str[index]​​ 这样的表达式是不可以被放在等号左侧的。如果尝试运行 ​​str[i] = 'D'​​ 会得到错误:​​cannot assign to str[i]​​。

因此,您必须先将字符串转换成字节数组,然后再通过修改数组中的元素值来达到修改字符串的目的,最后将字节数组转换回字符串格式。

例如,将字符串 "hello" 转换为 "cello":


s := "hello"
c := []byte(s)
c[0] = ’c’
s2 := string(c) //


所以,您可以通过操作切片来完成对字符串的操作。

字节数组对比函数

​Compare​​ 函数会返回两个字节数组字典顺序的整数对比结果,即 ​​0 if a == b, -1 if a < b, 1 if a > b​​。

func Compare(a, b[]byte) int {
for i:=0; i < len(a) && i < len(b); i++ {
switch {
case a[i] > b[i]:
return 1
case a[i] < b[i]:
return -1
}
}
//
switch {
case len(a) < len(b):
return -1
case len(a) > len(b):
return 1
}
return 0 //


搜索及排序切片和数组

​sort​​ 包来实现常见的搜索和排序操作。您可以使用 ​​sort​​ 包中的函数 ​​func Ints(a []int)​​ 来实现对 int 类型的切片排序。例如 ​​sort.Ints(arri)​​,其中变量 arri 就是需要被升序排序的数组或切片。为了检查某个数组是否已经被排序,可以通过函数 ​​IntsAreSorted(a []int) bool​​​​func Float64s(a []float64)​​ 来排序 float64 的元素,或使用函数 ​​func Strings(a []string)​​排序字符串元素。​​func SearchInts(a []int, n int) int​

当然,还可以搜索 float64 和字符串:


func SearchFloat64s(a []float64, x float64) int


您可以通过查看 ​​官方文档​​ 来获取更详细的信息。

​sort​

append 函数常见操作

我们在第 7.5 节提到的 append 非常有用,它能够用于各种方面的操作:

  1. 将切片 b 的元素追加到切片 a 之后:

​a = append(a, b...)​

  1. 复制切片 a 的元素到新的切片 b 上:

b = make([]T, len(a))
copy(b, a)

  1. 删除位于索引 i 的元素:

​a = append(a[:i], a[i+1:]...)​

  1. 切除切片 a 中从索引 i 至 j 位置的元素:

​a = append(a[:i], a[j:]...)​

  1. 为切片 a 扩展 j 个元素长度:

​a = append(a, make([]T, j)...)​

  1. 在索引 i 的位置插入元素 x:

​a = append(a[:i], append([]T{x}, a[i:]...)...)​

  1. 在索引 i 的位置插入长度为 j 的新切片:

​a = append(a[:i], append(make([]T, j), a[i:]...)...)​

  1. 在索引 i 的位置插入切片 b 的所有元素:

​a = append(a[:i], append(b, a[i:]...)...)​

  1. 取出位于切片 a 最末尾的元素 x:

​x, a = a[len(a)-1], a[:len(a)-1]​

  1. 将元素 x 追加到切片 a:

​a = append(a, x)​

因此,您可以使用切片和 append 操作来表示任意可变长度的序列。

从数学的角度来看,切片相当于向量,如果需要的话可以定义一个向量作为切片的别名来进行操作。

如果您需要更加完整的方案,可以学习一下 Eleanor McHugh 编写的几个包:​​slices​​​、​​chain​​​ 和 ​​lists​​。

切片和垃圾回收

切片的底层指向一个数组,该数组的实际体积可能要大于切片所定义的体积。只有在没有任何切片指向的时候,底层的数组内层才会被释放,这种特性有时会导致程序占用多余的内存。

示例 函数 ​​FindDigits​

var digitRegexp = regexp.MustCompile("[0-9]+")

func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
return digitRegexp.Find(b)
}


​[]byte​

想要避免这个问题,可以通过拷贝我们需要的部分到一个新的切片中:


func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
b = digitRegexp.Find(b)
c := make([]byte, len(b))
copy(c, b)
return







举报

相关推荐

0 条评论