这是我参与更文挑战的第 16 天,活动详情查看: 更文挑战mysql
上次咱们分享的内容咱回顾一下c++
要是对GO 对 ETCD 的编码还有点兴趣的话, 欢迎查看文章 GO 中 ETCD 的编码案例分享sql
他是一种基本类型(string 类型
),而且是一个不可改变的UTF-8字符序列shell
在众多编程语言里面,相信都少不了字符串类型编程
字符串,顾名思义就是一串字符,咱们要明白,字符也是分为中文字符和英文字符的数组
例如咱们在 C/C++
中 , 一个英文字符占 1 个字节,一个中文字符有的占 2 个字节,有的占3个字节markdown
用到 mysql
的中文字符,有的占 4 个字节数据结构
回过来看 GO 里面的字符串,字符也是根据英文和中文不同,一个字符所占用的字节数也是不同的,大致分为以下 2 种app
说到字符串的数据结构,咱们先来看看 GO 里面的字符串,是在哪一个包里面编程语言
不难发现,咱们随便在 GOLANG 里面 定义个string 变量
,就可以知道 string 类型是在哪一个包里面,例如
var name string
复制代码
GO 里面的字符串对应的包是 builtin
// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
// not nil. Values of string type are immutable.
type string string
复制代码
字符串这个类型,是全部8-bits
字符串的集合,一般但不必定表示utf -8
编码的文本
字符串能够为空,但不能为 nil
,此处的字符串为空是 ""
字符串类型的值是不可变的
另外,找到 string
在 GO 里面对应的源码文件中src/runtime/string.go
, 有这么一个结构体,只提供给包内使用,咱们能够看到string
的数据结构 stringStruct
是这个样子的
type stringStruct struct {
str unsafe.Pointer
len int
}
复制代码
整个结构体,就 2 个成员,**string **类型是否是很简单呢
是对应到字符串的首地址
这个就是不难理解,是字符串的长度
那么,在建立一个字符串变量的时候,stringStruct
是在哪里使用到的呢?
咱们看看 GO string.go 文件中的源码
//go:nosplit
func gostringnocopy(str *byte) string {
ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)} // 构建成 stringStruct
s := *(*string)(unsafe.Pointer(&ss)) // 强转成 string
return s
}
复制代码
//go:nosplit
func findnull(s *byte) int {
if s == nil {
return 0
}
// Avoid IndexByteString on Plan 9 because it uses SSE instructions
// on x86 machines, and those are classified as floating point instructions,
// which are illegal in a note handler.
if GOOS == "plan9" {
p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
l := 0
for p[l] != 0 {
l++
}
return l
}
// pageSize is the unit we scan at a time looking for NULL.
// It must be the minimum page size for any architecture Go
// runs on. It's okay (just a minor performance loss) if the
// actual system page size is larger than this value.
const pageSize = 4096
offset := 0
ptr := unsafe.Pointer(s)
// IndexByteString uses wide reads, so we need to be careful
// with page boundaries. Call IndexByteString on
// [ptr, endOfPage) interval.
safeLen := int(pageSize - uintptr(ptr)%pageSize)
for {
t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
// Check one page at a time.
if i := bytealg.IndexByteString(t, 0); i != -1 {
return offset + i
}
// Move to next page
ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
offset += safeLen
safeLen = pageSize
}
}
复制代码
简单分为 2 步:
从上述官方说明中,咱们能够看到,字符串类型的值是不可变的
但是这是为啥呢?
咱们之前在写C/C++
的时候,为啥能够开辟空间存放多个字符,而且还能够修改其中的某些字符呢?
但是在 C/C++
里面的字面量也是不能够改变的
GO 里面的 string 类型,是否是也和 字面量同样的呢?咱们来看看吧
字符串类型,自己也是拥有对应的内存空间的,那么修改string
类型的值应该是要支持的。
但是,XDM
在 Go 的实现中,string
类型是不包含内存空间,只有一个内存的指针,这里就有点想C/C++里面的案例:
char * str = "XMTONG"
复制代码
上述的 str
是绝对不能作修改的,str
只是做为可读,不能写的
在GO 里面的字符串,就与上述相似
这样作的好处是 string
变得很是轻量,能够很方便的进行传递而不用担忧内存拷贝(这也避免了内存带来的诸多问题)
GO 中的 string
类型通常是指向字符串字面量
字符串字面量存储位置是在虚拟内存分区的只读段上面,而不是堆或栈上
所以,GO 的 string
类型不可修改的
但是咱们想想,要是在GO 里面字符串全都是只读的,那么咱们如何动态修改一些咱们须要改变的字符呢,这岂不是缺陷了
别慌
GO 里面还有byte数组,[]byte
这里顺带说一下
上述 char * str = "XMTONG"
str
所占字节数(C/C++中是经过 sizeof()
来计算的)的话,那就是 7 ,由于尾巴后面还有一个'\0'计算机中有这样的对应关系,简单提一下:
1 Bytes = 8 bit
1 K = 1024 Bytes
1 M = 1024 K
1 G = 1024 M
缘由正如上述咱们说到的,若是全是一些只读的字面量,那么咱们编码的时候就没得玩了
另外,也是根据使用字符串的场景缘由,单是string没法知足全部的场景,所以得有一个咱们能够修改里面值的 []byte 来弥补一下
说到这里,咱们应该就知道了,string
和[]byte
都是能够表示字符串,没毛病 ,
不过,他们毕竟对应不一样的数据结构,使用方式也有必定的区别,GO 提供的对应方法也是不尽相同
咱们来看看什么场景用 string 类型, 啥场景 使用 []byte 类型
使用到 string 类型的 地方:
nil
作比较,所以,不用到nil
的时候,也可使用 string 类型使用到 []byte 类型的 地方:
缘由以下:
看到这里,分别了解了 string
类型, 和 []byte
类型的应用场景
毋庸置疑,咱们编码过程当中,确定少不了对他们作相互转换,咱们来看看在 GO ,里面如何使用
package main
import (
"fmt"
)
func main(){
var str string
str = "XMTONG"
strByte := []byte(str)
for _,v :=range strByte{
fmt.Printf("%x ",v)
}
}
复制代码
代码输出为:
58 4d 54 4f 4e 47
复制代码
上述代码转成 []byte
以后是一个字节,一个字节的
将每个字节的值用十六进制打印出来,咱们能够看到,XMTONG
对应 584d544f4e47
[]byte
转字符串在GO 里面那就更简单了
func main(){
name := []byte("XMTONG")
fmt.Println(string(name))
}
复制代码
不管什么语言,对于字符串大概涉及以下几种操做,如有误差,还请指正:
具体的函数使用方法也比较简单,推荐你们感兴趣的能够直接看go 的开发文档,须要的时候去查一下便可。
GO 的标准开发文档,在搜索引擎里面仍是比较容易搜索到的
[]byte
的由来和应用场景[]byte
相互转换朋友们,你的支持和鼓励,是我坚持分享,提升质量的动力
好了,本次就到这里,下一次 GO 中 slice 的实现原理分享
技术是开放的,咱们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是小魔童哪吒,欢迎点赞关注收藏,下次见~