Golang 语言基础之六: string, pointer

Xiaohui Wang · · 5031 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Golang 语言基础之六: string, pointer

Golang 语言基础系列:

字符串类型 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 的使用方法我们看个例子:

package main

import "fmt"

func main() {

	// 默认 string 类型对象零值为空字符串,尾部不包含 `\0`
	var emptyStr string
	fmt.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` 类型,取类型后为 int32
	v_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 可以对指向不同类型对象的指针进行转换
  • 指针不能进行 +- 运算,以保证安全性。

使用实例如下:

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	// 检查指针对象的零值为 nil
	var p *int
	fmt.Println("The zero value of a pointer is: ", p)

	// 指向指针的指针
	pp := &p
	fmt.Printf("The type of a pointer points another pointer is: %T\n", pp)

	// 指针对象赋值
	intVar := 100000000
	p = &intVar
	fmt.Println("After assignment, p is: ", p)
	fmt.Println("The value pointer p points is: ", *p)

	// 使用 unsafe.Pointer 方法可以将一个类型的指针转化为 Pointer
	// Pointer 可以被转化为任意类型的指针。
	// 注意由于 int 为 int32 的别名,占 4 个字节,所以我们将其转化为含有 4 个字节元素的 `byte` 数组指针
	var strP *[4]byte
	strP = (*[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)

	// 指针指向的对象内容使用 `.` 而不是 `->` 来进行访问
	type User struct {
		name string
	}
	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,建议阅读这篇文章,里面做了很好的总结。

参考资料

-- EOF --

声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: Golang 语言基础之六: string, pointer


有疑问加站长微信联系(非本文作者)

本文来自:Ross's Page

感谢作者:Xiaohui Wang

查看原文:Golang 语言基础之六: string, pointer

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

5031 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传