字符串
字符串是不可变字节(byte)序列,本身是一个复合结构。默认以UTF-8编码存储unicode字符。它的默认值是“”,而不是nil。字符串底层就是⼀个byte数组,所以可以和[]byte类型互相转换。
使用“ ‘ ”定义不做转义处理的原始字符串,支持跨行。
func main() {
s := 'line\r\n,
line 2'
println(s);
}
输出:
line\r\n,
line 2
字符串之中的字符是不能修改的,但是可以将其转换为可变类型([]rune或[]byte),完成之后再转换回来。但是不管如何转换,都需要重新分配内存,并复制数据。字符串是由byte字节组成,所以字符串的长度是byte字节的长度。rune类型用来表示utf8字符,一个rune字符由1个或多个byte组成。
func pp(format string, ptr interface{}) {
p := reflect.ValueOf(ptr).Pointer()
h := (*uintptr)(unsafe.Pointer(p))
fmt.Printf(format, *h)
}
func main() {
s :="hello,world!"
pp("s: %x\n", &s)
bs := []byte(s)
s2 := string(bs)
pp(“string to []byte, bs; %x\n”, &bs)
pp(“[]byte to string, s2; %x\n”, &s2)
rs := []rune(s)
s3 := string(rs)
pp(“string to []rune, rs; %x\n”, &rs)
pp(“[]rune to string, s3; %x\n”, &s3)
}
有些时候,转换会降低算法的性能,因此可以考虑使用“非安全”方法进行改善。
func toString(bs []byte) string {
return *(*string)(unsafe.Pointer(&bs))
}
func main() {
bs := []byte("hello,world!")
S := toString(bs)
printDataPointer("bs: %x\n", &bs)
printDataPointer("s : %x\n", &s)
}
该方法利用了[]byte和string头结构“部分相同”,以非安全的指针类型转换来实现类型“变更”,避免了底层数组复制。在高并发压力下能有效改善执行性能。
使用+拼接字符串也会产生性能问题,每次都必须重新分配内存。可以预分配足够的内存空间,使用strings.Join函数,统计所有参数长度,并一次性完成内存分配操作。
数组
数组是同一类型的元素集合。Go数组下标也是从0开始,因此长度为n的数组下标范围是[0,n-1]。整数数组中的元素默认初始化为0,字符串数组中的元素默认初始化为“”。
var a [3]int //定义一个数组
数组的初始化有以下几种:
//数组初始化
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
var a [3]int = [3]int{10, 20, 30} //定义时数组初始化
a := [3]int{10, 20, 30} //定义时数组初始化
a := […]int{10, 20, 30} //定义时数组初始化
a := [3]int{10} //定义时数组初始化,未提供初始值的自动初始化为0
a := [3]int{2:10} //定义时数组初始化,制定索引位置初始化
数组长度是类型的⼀部分
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
var b [5]int
b = a //a、b是不同类型的数组,不能赋值
数组内置函数len和cap都返回第一维长度。
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
fmt.Printf(“len:%d\n”, len(a))
数组的遍历
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
for i := 0; i < len(a); i++ { //遍历1
}
for index, val := range a { //遍历2
}
var a [3][2]int
a[0][0] = 10
a[0][1] = 20
a[1][0] = 30
a[1][1] = 30
a[2][0] = 30
a[2][1] = 30
for index, val := range a { //二维数组遍历
}
数组的拷贝与传参
//数组是值类型
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
b := a
//b拷⻉了数组a中所有元素
b[0] = 1000
fmt.Println(a, b)
//数组是值类型,函数传参也会拷贝
func main() {
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
modify(a)
fmt.Println(a)
}
func modify(b [3]int) {
b[0] = 1000
return
}