Golang基础 基础数据类型之值类型

值类型通常是存储在内存栈空间中的键值对,将变量的实际值存储在栈中随取随用,但在赋值或拷贝时产生的是独立的键值对副本,修改新数据旧值不受影响。

类型长度/Byte默认值说明
bool1false
byte10uint8
rune40Unicode Code Point, int32
int, uint4/8032 或 64 位
int8, uint810-128 ~ 127, 0 ~ 255,byte是uint8 的别名
int16, uint1620-32768 ~ 32767, 0 ~ 65535
int32, uint3240-21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名
int64, uint6480
float3240.0
float6480.0
complex648
complex12816
stringUTF-8 字符串
array固定长度的数组

01 布尔类型

和C++一样,Golang中也使用bool保留字声明布尔类型的数据,这种数据只有truefalse两种值,分别表示“真”和“假”。

布尔类型有如下特点:

  • 布尔类型的默认值是false

  • 布尔类型无法参与任何形式数值运算

  • 布尔类型无法与其他任何类型进行转换

func BoolExp() {
	var flag bool
	if !flag {
		fmt.Println("flag is false")
	}
}

02 字符类型

组成每个字符串的元素叫做“字符”,在C/C++这种类型被称为字符类型用保留字char表示,在Golang中用两种方式声明字符类型:

  • byte 类型:和C/C++中的char相似只能表示 ASCII 码表中的字符,是 uint8 的别名类型

  • rune类型:则是Golang中特有的字符类型能够表示 UTF-8 中的任一字符, 是 int32 的别名类型

    byte 类型虽然表示范围较小但在处理字符串性能上更优;而 rune 类型则在处理中文、日文等其他Unicode复合字符串时更加方便。Golang通过这两种字符类型让其在处理字符串时性能和扩展性都有照顾。

func CharExp() {
	var a byte = 'A'
	var b rune = 'A'

	fmt.Printf("sizeof a is %d bytes\n", unsafe.Sizeof(a))
	fmt.Printf("sizeof b is %d bytes\n", unsafe.Sizeof(b))
}

03 整型

Golang中对数据类型进行更明确的命名,其中国整型分为以下两个大类:

  • 有符号整型:int8int16int32int64

  • 无符号整型:uint8uint16uint32uint64

其中uint8byte类型及C/C++中的char类型;int16对应C/C++中的short类型;int32对应C/C++中的int类型;int64 对应C/C++中的long类型。

func IntExp() {
	var a int8 = 1
	var b int16 = 1
	var c int32 = 1
	var d int64 = 1
	var e int = 1

	fmt.Printf("size of a is %d bytes", unsafe.Sizeof(a))
	fmt.Printf("size of b is %d bytes", unsafe.Sizeof(b))
	fmt.Printf("size of c is %d bytes", unsafe.Sizeof(c))
	fmt.Printf("size of d is %d bytes", unsafe.Sizeof(d))
	fmt.Printf("size of e is %d bytes", unsafe.Sizeof(e))
}

哪些情况下使用int和uint:

Golang 有根据平台字节长度差异自动匹配特定平台整型长度的类型:int和uint

在使用int和uint类型时,不能假定它是32位或64位的整型,而是考虑int和uint可能在不同平台上的差异。

逻辑对整型范围没有特殊需求。例如,对象的长度使用内建len()函数返回,这个长度可以根据不同平台的字节长度进行变化。实际使用中,切片或map的元素数量等都可以用int来表示。

反之,在二进制传输、读写文件的结构描述时,为了保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用int和uint。

04 浮点类型

Golang支持两种浮点型数:float32float64分别对应C/C++中的floatdouble两种浮点类型。

float32 的浮点数的最大范围约为3.4e38,可以使用常量定义:math.MaxFloat32float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64

05 复数类型

Golang中增加了对复数表示的支持,针对复数实部和虚部float32float64两种不同的精度提供了两种复数类型:complex64complex128

复数类型可以通过realimag两个内置函数分别获取complex的实部和虚部

var a complex128 = complex(1, 2) 
var b complex128 = complex(3, 4) 

fmt.Println(a*b) 
fmt.Println(real(a*b))
fmt.Println(imag(a*b))

06 字符串类型

不同于C/C++中字符串以第三方库出现,Golang中将字符串作为原生数据类型,并实现基于UTF-8编码,极大简化了字符串的处理。

6.1 定义字符串

字符串类型的保留字是string,可以直接使用双引号""来定义字符串。

func StringExp() {
	var str1 string = "hello, world"
	var str2 = "golang \\"
	str3 := "go"

	fmt.Println(str1, "printed by", str2, str3)
}

上面的例子中 str2 的定义中使用到反斜杠的转义符\\,除此之外字符串中常见的转义符包含回车、换行、单双引号、制表符等。

转义含义
\r回车符(返回行首)
\n换行符(直接跳到下一行的同列位置)
\t制表符(tab键)
单引号
"双引号
\反斜杠

定义多行字符串:Golang中可以使用反引号定义一个多行字符串,但反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。

func MultiRows() {
	var rows = `hello \n
		world!
		\t golang
	`

	fmt.Println(rows)
}

6.2 字符串操作

方法介绍
len(str)求长度
+ 或 fmt.Sprintf拼接字符串
strings.Split分割
strings.Contains判断是否包含
strings.HasPrefix,strings.HasSuffix前缀/后缀判断
strings.Index(),strings.LastIndex()子串出现的位置
strings.Join(a[]string, sep string)join操作

(1)获取字符串长度

Golang可以使用内置函数len()来获取字符串的长度,也可以使用RuneCountInString()来获取 Unicode 编码的字符串长度。

len()获取的是字符串的 ASCII 字符个数或者整个字符串所占空间的字节长度,如下例子中,str1是纯ASCII字符串其字符个数为12,则len(str1)的返回值是12;str2则是Unicode编码的字符串,"你好"字符串以 UTF-8 格式保存,每个中文字符占用 3 个字节,因此len(str2)的返回值是 6。

func StringLen() {
	var str1 string = "hello, world"
	str2 := "你好"

	fmt.Printf("the length of str1 is %d, str2 is %d\n", len(str1), len(str2))
	fmt.Printf("the length of str1 is %d, str2 is %d\n", len(str1), utf8.RuneCountInString(str2))
}

如果想要获取 Unicode 字符串的字符个数,则需要使用 UTF-8 包中的 RuneCountInString() 方法,统计字符个数,及一般意义上的字符串长度。

(2)遍历字符串

Golang中遍历字符串可以通过标准索引法来获取,即用方括号运算符[]找到对应索引位置的字符,字符串索引从 0 开始计数。

func StringTraversal() {
	str1 := "hello, world"
	str2 := "hello, 世界"
	for i := 0; i < len(str1); i++ {
		fmt.Printf(" %c:%d", str1[i], str1[i])
	}
	fmt.Println()
	for i := 0; i < len(str2); i++ {
		fmt.Printf(" %c:%d", str2[i], str2[i])
	}
	fmt.Println()
	for _, ch := range str2 {
		fmt.Printf(" %c:%d", ch, ch)
	}
	fmt.Println()
}

比较str1str2的标准索引遍历方式,后者中Unicode编码字符出现乱码情况,可以得出该方式仅适用于纯 ASCII 码字符串 。Unicode 字符串遍历使用 for range

字符串底层原理:这是由于字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成,一个中文汉字由3~4个字节组成,所以不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现乱码情况。

(3)截取子字符串

Golang字符串的截取可以使用标准索引法,使用索引[m:n]表示截取索引大于等于m小于n的子串即str[m,n),如果字符串是 Unicode 编码则需要把包含复杂字符的字节数全都包含在截取区间内否则会出现乱码情况。

func StringSubStr() {
	str := "hello, 世界"
	fmt.Printf("str[0:5]:%s\n", str[0:5])
	fmt.Printf("str[0:8]:%s\n", str[0:8])
	fmt.Printf("str[0:10]:%s\n", str[0:10])
	fmt.Printf("str[7:]:%s\n", str[7:])
}

(4)拼接字符串

Golang中字符串的拼接同样可以直接使用加号运算发+将其右侧字符串拼接到其左侧字符串末尾生成一个新的字符串。也可以使用+=运算符在当前字符串后直接添加一个字符串。

func StringAppend() {
    str1 := "hello, "
    str2 := "world!"
    str := str1 + str2
    fmt.Printf("%s + %s = %s\n", str1, str2, str)
    str += "你好,世界!"
    fmt.Printf("new string: %s\n", str)
}

(5)修改字符串

Golang中要修改字符串,需要先将其转换成[]rune[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组。

func StringChange() {
	str1 := "hello, world"
	byteStr1 := []byte(str1)
	byteStr1[1] = 'E'
	fmt.Println("change str1: ", string(byteStr1))

	str2 := "hello, 世界"
	runeStr2 := []rune(str2)
	runeStr2[7] = '国'
	fmt.Println("change str2: ", string(runeStr2))
}

更多字符串操作参考标准库stringsstrings package - strings - Go Packages

//判断两个字符串是否相同,忽略大小写。
func EqualFold(s, t string) bool
//判断字符串p的前缀是否为prefix
func HasPrefix(s, prefix string) bool
//判断字符串的结尾是否为suffix
func HasSuffix(s, suffix string) bool
//判断字符串s是否包含substr
func Contains(s, substr string) bool
//判断字符串中是否包括rune字符
func ContainsRune(s string, r rune) bool
//字符串s中是否包含chars任何一个字符
func ContainsAny(s, chars string) bool
//统计s中有多少sep个字符串
func Count(s, sep string) int
//返回在s中sep的首字母位置
func Index(s, sep string) int
//返回字符c在s中的位置
func IndexByte(s string, c byte) int
//返回字符r在s中的位置
func IndexRune(s string, r rune) int
//返回字符串chars中在s中出现最早的位置
func IndexAny(s, chars string) int
//返回符合函数规范的索引
func IndexFunc(s string, f func(rune) bool) int
//任意的字符chars在s中最后一个字符的索引
func LastIndexAny(s, chars string) int
//转换成小写字母
func ToLower(s string) string
//转换成大写字母
func ToUpper(s string) string
//字符串中的指定字符,最后一个参数为替换的个数,如果为-1,则全部替换
func Replace(s, old, new string, n int) string
//将所有包含sutset的开头和结尾的字符全部删除
func Trim(s string, cutset string) string
//删除全部空白
func TrimSpace(s string) string
//删除根据函数进行字符串开头和结尾的删除
func TrimFunc(s string, f func(rune) bool) string
//将字符串左侧的指定字符删除
func TrimLeft(s string, cutset string) string
//将字符串左侧符合函数的字符进行删除
func TrimLeftFunc(s string, f func(rune) bool) string
//将字符串左侧的prefix进行删除
func TrimPrefix(s, prefix string) string
//按字符串之间的空白进行分割,返回数组
func Fields(s string) []string
//按字符串中符合函数的字符进行分割
func FieldsFunc(s string, f func(rune) bool) []string
//将字符串中的sep作为分割符,进行分割,返回数组
func Split(s, sep string) []string
//按照sep进行分割,并且可以指定分割的次数
func SplitN(s, sep string, n int) []string
//前些个分割字符串是将分割符进行删除,此函数,将在分割符后进行分割。
func SplitAfter(s, sep string) []string
//不删除分割符,并指定分割次数
func SplitAfterN(s, sep string, n int) []string
//将字符串型数组,按照指定连接符进行连接
func Join(a []string, sep string) string

07 定长数组

7.1 定义数组

Golang中数组 Array 是同一种数据类型的固定长度的序列,所以定义数组时必须指定存放元素的类型和容量,其格式如下所示:

var 变量名称 [数组容量]数据类型

// example:
var arr0 [5]int
var arr1 [3]bool

如果在定义数组时不对其进行初始化,则使用默认值填充,整型默认值是0、浮点型默认值是0.0、布尔类型默认值是false、字符串默认值则是空串。

使用大括号初始化数组:即在大括号中定义好和数组指定的数据类型与数组容量一致的值

var arr0 = [5]int{1, 2, 3, 4, 5}
var arr1 [3]bool
fmt.Println("arr0:", arr0, "\narr1:", arr1)

局部初始化:初始化元素个数小于指明的容量时,数组在初始化过程中会用默认值填充补齐;如果数组声明时未指明容量或者使用...设置数组容量,则数组在初始化过程中会根据初始值自动判断数组的容量。

var arr2 = [7]int{1, 2, 3, 4, 5, 6, 7}
var arr3 = [7]int{1, 2, 3}
var arr4 = []int{1, 2, 3}
var arr5 = [...]int{1, 2, 3}
fmt.Println("arr2:", arr2, "\narr3:", arr3, "\narr4:", arr4, "\narr5:", arr5)

通过指定索引对应的值初始化数组:在大括号中指定索引对应的值,未指定索引的值会用默认值填充。

arr6 := [5]int{0: 1, 3: 4}
arr7 := []int{0: 1, 4: 5, 8: 9}
fmt.Println("arr6:", arr6, "\narr7:", arr7)

7.2 定义多维数组

Golang中可以通过增加容量维度来定义多维数组,声明语法格式如下所示:

var 变量名称 [一维容量][二维容量]...[N维容量]数据类型

// example:
var arr8 [3][3]int
var arr9 [3][3][3]bool

多维数组的初始化与一维一致,满足嵌套结构

arr8 := [3][3]int{
		{1, 2, 3},
		{4, 5, 6},
		{0: 7, 2: 9},
	}
fmt.Println("arr8:", arr8)

多维数组容量声明时仅能省略第一维度,其他维度不可省略

arr10 := [...][3]int{
		{1, 2, 3},
		{4, 5, 6},
		{0: 7, 2: 9},
	}
arr11 := [][3]int{
		{1, 2, 3},
		{0: 7, 2: 9},
	}
fmt.Println("arr10:", arr10, "\narr11:", arr11)

7.3 遍历数组

使用标准索引法遍历数组:这种方式需要使用len()内置函数获取数组长度,然后使用[]中括号运算符获取索引元素。

func ArrayTraversal() {
	var arr0 = [5]int{1, 2, 3, 4, 5}
	for i := 0; i < len(arr0); i++ {
		fmt.Printf("%d:%d ", i, arr0[i])
	}

	arr8 := [3][3]int{
		{1, 2, 3},
		{4, 5, 6},
		{0: 7, 2: 9},
	}
	for i := 0; i < len(arr8); i++ {
		for j := 0; j < len(arr8[0]); j++ {
			fmt.Printf("(%d,%d):%d ", i, j, arr8[i][j])
		}
	}
}

使用for range遍历数组

func ArrayTraversal() {
	var arr0 = [5]int{1, 2, 3, 4, 5}
	for _, e := range arr0 {
		fmt.Printf("%d", e)
	}

	arr8 := [3][3]int{
		{1, 2, 3},
		{4, 5, 6},
		{0: 7, 2: 9},
	}
	for k1, row := range arr8 {
		for k2, elem := range row {
			fmt.Printf("(%d,%d):%d ", k1, k2, elem)
		}
	}
}

参考资料

基本类型 · Go语言中文文档

变量类型之值类型与引用类型

Go语言字符串

数组Array · Go语言中文文档

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王清欢Randy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值