Golang 语言基础之六: string, pointer
Xiaohui Wang · · 5733 次点击 · · 开始浏览Golang 语言基础之六: string, pointer
Golang 语言基础系列:
- Golang 语言基础之一: type, variable, constant
- Golang 语言基础之二: for, ifelse, switch
- Golang 语言基础之三: array, slice
- Golang 语言基础之四: map, range
- Golang 语言基础之五: function
- Golang 语言基础之六: string, pointer
- Golang 语言基础之七: struct, method
- Golang 语言基础之八: interface
- Golang 语言基础之九: error, panic, recover
- Golang 语言基础之十: goroutine, channel
字符串类型 string
字符串在 Golang 源码文件 runtime.h 中的定义如下:
struct String
{
byte* str;
intgo len;
};可以看出,其内部包含一个 byte 类型的数组,Golang 采用 UTF-8 编码方式。和 C/C++ 的字符数组不同,Golang 的字符数组有下面的特点:
string类型的零值为空字符串。- 不能用序号获取字节元素指针,&s[i] 为非法。
string是不可变类型,其内部存储数据的字符数组无法修改。如需修改,需要将string对象转化为rune类型(如果字符串含有非 ASIC 码字符)或者byte类型(如果字符串由 ASIC 码字符组成)的slice对象。修改后的字符数组会重新分配内存保存在一个新的字符串对象中。- 字节数组尾部不包含
0円
关于 string 的使用方法我们看个例子:
packagemainimport"fmt"funcmain(){// 默认 string 类型对象零值为空字符串,尾部不包含 `0円`varemptyStrstringfmt.Println("emptyStr is: ",emptyStr)fmt.Println("len(emptyStr) is: ",len(emptyStr))// 声明 string 对象并初始化,使用下标访问。// 注意,如果字符串中包含中文等非 ASIC 码的字符,则使用下标索引会导致与期望不符的结果// 字符串是 UTF-8 编码,所以非 ASIC 码字符不止一个字节,而使用下标获得的是每个字节的内容。str:="I like 高圆圆"fmt.Println("string object is: ",str)fmt.Println("len(str) = : ",len(str))fmt.Println("str[1]: ",str[1])// 使用 ` 语法可以声明无转义的字符串str=`I
Love
Golang`fmt.Println("str: ",str)// 修改字符串,注意将字符串分别转化为 `rune` 和 `byte` 的 `slice` 对象。// 它们的长度是不相等的,`rune` 切片对象的长度等于原始 `string` 对象中的字符个数。// `byte` 切片对象的长度等于原始 `string` 对象在内存中所占的字节数,其值和 `len` 取得的 `string` 对象长度相等// 如果 `string` 对象中有非 ASIC 码,则两者的长度是不相等的。// 所以为了保证兼容性,最好将 `string` 对象转化为 `rune` 切片对象后进行修改。str="I like 高圆圆"fmt.Println("Before modification, str: ",str)fmt.Println("len(str) = : ",len(str))rune_str:=[]rune(str)byte_str:=[]byte(str)fmt.Println("len([]rune(str)) = ",len(rune_str))fmt.Println("len([]byte(str)) = ",len(byte_str))rune_str[7]='范'rune_str[8]='冰'rune_str[9]='冰'fmt.Println("After modification, str: ",string(rune_str))// 单引号中的字符常量为 `rune` 类型,取类型后为 int32v_char:='g'fmt.Printf("The type of v_char is %T\n",v_char)}将上面的代码存入源文件 string.go 并使用 go run string.go 可以看到下面的输入:
emptyStr is:
len(emptyStr) is: 0
string object is: I like 高圆圆
len(str) = : 16
str[1]: 32
str: I
Love
Golang
Before modification, str: I like 高圆圆
len(str) = : 16
len([]rune(str)) = 10
len([]byte(str)) = 16
After modification, str: I like 范冰冰
The type of v_char is int32指针类型 pointer
Golang 中的指针和 C/C++ 相同的地方有:
- 指针 *T
- 指针的指针 **T
- 通过 operator
*访问指针指向的对象,&取对象的地址
不同的地方有:
- 指针的默认值为
nil,而不是NULL - 指针不能进行加减运算,指针所指对象的成员使用
.访问而非-> - 使用
unsafe.Pointer可以对指向不同类型对象的指针进行转换 - 指针不能进行
+、-运算,以保证安全性。
使用实例如下:
packagemainimport("fmt""unsafe")funcmain(){// 检查指针对象的零值为 nilvarp*intfmt.Println("The zero value of a pointer is: ",p)// 指向指针的指针pp:=&pfmt.Printf("The type of a pointer points another pointer is: %T\n",pp)// 指针对象赋值intVar:=100000000p=&intVarfmt.Println("After assignment, p is: ",p)fmt.Println("The value pointer p points is: ",*p)// 使用 unsafe.Pointer 方法可以将一个类型的指针转化为 Pointer// Pointer 可以被转化为任意类型的指针。// 注意由于 int 为 int32 的别名,占 4 个字节,所以我们将其转化为含有 4 个字节元素的 `byte` 数组指针varstrP*[4]bytestrP=(*[4]byte)(unsafe.Pointer(p))fmt.Println("After \"(*[4]byte)(unsafe.Pointer(p))\", *[4]byte pointer strP is: ",strP)fmt.Println("After \"(*[4]byte)(unsafe.Pointer(p))\", *[4]byte pointer strP points to: ",*strP)// 指针指向的对象内容使用 `.` 而不是 `->` 来进行访问typeUserstruct{namestring}userP:=&User{"Xiaohui",}fmt.Println("Before change, The value userP points to is: ",*userP)userP.name="Ross"fmt.Println("After change, The value userP points to is: ",*userP)}将上面的代码存入源文件 pointer.go 并使用 go run pointer.go 可以看到下面的输入:
The zero value of a pointer is: <nil>
The type of a pointer points another pointer is: **int
After assignment, p is: 0xc20800a240
The value pointer p points is: 100000000
After "(*[4]byte)(unsafe.Pointer(p))", *[4]byte pointer strP is: &[0 225 245 5]
After "(*[4]byte)(unsafe.Pointer(p))", *[4]byte pointer strP points to: [0 225 245 5]
Before change, The value userP points to is: {Xiaohui}
After change, The value userP points to is: {Ross}关于 unsafe.Pointer,建议阅读这篇文章,里面做了很好的总结。
参考资料
- The Go Programming Language
- 学习 Go 语言 中文版
- Go in Action 中文版
- The way to Go 中文版
- Go by Example
- Organizing Go code
- Testing Techniques
- Go 语言分享
- Go 学习笔记
- Go 语言简介
- Tony Bai 的博客
-- EOF --
声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: Golang 语言基础之六: string, pointer
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
Golang 语言基础之六: string, pointer
Golang 语言基础系列:
- Golang 语言基础之一: type, variable, constant
- Golang 语言基础之二: for, ifelse, switch
- Golang 语言基础之三: array, slice
- Golang 语言基础之四: map, range
- Golang 语言基础之五: function
- Golang 语言基础之六: string, pointer
- Golang 语言基础之七: struct, method
- Golang 语言基础之八: interface
- Golang 语言基础之九: error, panic, recover
- Golang 语言基础之十: goroutine, channel
字符串类型 string
字符串在 Golang 源码文件 runtime.h 中的定义如下:
struct String
{
byte* str;
intgo len;
};可以看出,其内部包含一个 byte 类型的数组,Golang 采用 UTF-8 编码方式。和 C/C++ 的字符数组不同,Golang 的字符数组有下面的特点:
string类型的零值为空字符串。- 不能用序号获取字节元素指针,&s[i] 为非法。
string是不可变类型,其内部存储数据的字符数组无法修改。如需修改,需要将string对象转化为rune类型(如果字符串含有非 ASIC 码字符)或者byte类型(如果字符串由 ASIC 码字符组成)的slice对象。修改后的字符数组会重新分配内存保存在一个新的字符串对象中。- 字节数组尾部不包含
0円
关于 string 的使用方法我们看个例子:
packagemainimport"fmt"funcmain(){// 默认 string 类型对象零值为空字符串,尾部不包含 `0円`varemptyStrstringfmt.Println("emptyStr is: ",emptyStr)fmt.Println("len(emptyStr) is: ",len(emptyStr))// 声明 string 对象并初始化,使用下标访问。// 注意,如果字符串中包含中文等非 ASIC 码的字符,则使用下标索引会导致与期望不符的结果// 字符串是 UTF-8 编码,所以非 ASIC 码字符不止一个字节,而使用下标获得的是每个字节的内容。str:="I like 高圆圆"fmt.Println("string object is: ",str)fmt.Println("len(str) = : ",len(str))fmt.Println("str[1]: ",str[1])// 使用 ` 语法可以声明无转义的字符串str=`I
Love
Golang`fmt.Println("str: ",str)// 修改字符串,注意将字符串分别转化为 `rune` 和 `byte` 的 `slice` 对象。// 它们的长度是不相等的,`rune` 切片对象的长度等于原始 `string` 对象中的字符个数。// `byte` 切片对象的长度等于原始 `string` 对象在内存中所占的字节数,其值和 `len` 取得的 `string` 对象长度相等// 如果 `string` 对象中有非 ASIC 码,则两者的长度是不相等的。// 所以为了保证兼容性,最好将 `string` 对象转化为 `rune` 切片对象后进行修改。str="I like 高圆圆"fmt.Println("Before modification, str: ",str)fmt.Println("len(str) = : ",len(str))rune_str:=[]rune(str)byte_str:=[]byte(str)fmt.Println("len([]rune(str)) = ",len(rune_str))fmt.Println("len([]byte(str)) = ",len(byte_str))rune_str[7]='范'rune_str[8]='冰'rune_str[9]='冰'fmt.Println("After modification, str: ",string(rune_str))// 单引号中的字符常量为 `rune` 类型,取类型后为 int32v_char:='g'fmt.Printf("The type of v_char is %T\n",v_char)}将上面的代码存入源文件 string.go 并使用 go run string.go 可以看到下面的输入:
emptyStr is:
len(emptyStr) is: 0
string object is: I like 高圆圆
len(str) = : 16
str[1]: 32
str: I
Love
Golang
Before modification, str: I like 高圆圆
len(str) = : 16
len([]rune(str)) = 10
len([]byte(str)) = 16
After modification, str: I like 范冰冰
The type of v_char is int32指针类型 pointer
Golang 中的指针和 C/C++ 相同的地方有:
- 指针 *T
- 指针的指针 **T
- 通过 operator
*访问指针指向的对象,&取对象的地址
不同的地方有:
- 指针的默认值为
nil,而不是NULL - 指针不能进行加减运算,指针所指对象的成员使用
.访问而非-> - 使用
unsafe.Pointer可以对指向不同类型对象的指针进行转换 - 指针不能进行
+、-运算,以保证安全性。
使用实例如下:
packagemainimport("fmt""unsafe")funcmain(){// 检查指针对象的零值为 nilvarp*intfmt.Println("The zero value of a pointer is: ",p)// 指向指针的指针pp:=&pfmt.Printf("The type of a pointer points another pointer is: %T\n",pp)// 指针对象赋值intVar:=100000000p=&intVarfmt.Println("After assignment, p is: ",p)fmt.Println("The value pointer p points is: ",*p)// 使用 unsafe.Pointer 方法可以将一个类型的指针转化为 Pointer// Pointer 可以被转化为任意类型的指针。// 注意由于 int 为 int32 的别名,占 4 个字节,所以我们将其转化为含有 4 个字节元素的 `byte` 数组指针varstrP*[4]bytestrP=(*[4]byte)(unsafe.Pointer(p))fmt.Println("After \"(*[4]byte)(unsafe.Pointer(p))\", *[4]byte pointer strP is: ",strP)fmt.Println("After \"(*[4]byte)(unsafe.Pointer(p))\", *[4]byte pointer strP points to: ",*strP)// 指针指向的对象内容使用 `.` 而不是 `->` 来进行访问typeUserstruct{namestring}userP:=&User{"Xiaohui",}fmt.Println("Before change, The value userP points to is: ",*userP)userP.name="Ross"fmt.Println("After change, The value userP points to is: ",*userP)}将上面的代码存入源文件 pointer.go 并使用 go run pointer.go 可以看到下面的输入:
The zero value of a pointer is: <nil>
The type of a pointer points another pointer is: **int
After assignment, p is: 0xc20800a240
The value pointer p points is: 100000000
After "(*[4]byte)(unsafe.Pointer(p))", *[4]byte pointer strP is: &[0 225 245 5]
After "(*[4]byte)(unsafe.Pointer(p))", *[4]byte pointer strP points to: [0 225 245 5]
Before change, The value userP points to is: {Xiaohui}
After change, The value userP points to is: {Ross}关于 unsafe.Pointer,建议阅读这篇文章,里面做了很好的总结。
参考资料
- The Go Programming Language
- 学习 Go 语言 中文版
- Go in Action 中文版
- The way to Go 中文版
- Go by Example
- Organizing Go code
- Testing Techniques
- Go 语言分享
- Go 学习笔记
- Go 语言简介
- Tony Bai 的博客
-- EOF --
声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: Golang 语言基础之六: string, pointer