七叶笔记 » golang编程 » Golang之数据类型

Golang之数据类型

写在前面:

0x01 — 数据类型

Golang中数据类型比较多,下面会通过示例展示下:

1. 布尔类型

布尔类类型标识为bool, 其值为 true或false,定义使用如下:

 package test

import (
   "fmt"
   "testing"
   "time"
)

func TestBoolType(t *testing.T) {
   var b, c, d, e bool
   ct := time.Now().Unix() // 获取时间戳
   t.Log("当前时间戳:", ct)
   b = false
   c = true
   e = ct < 1616 // 如果运算结果是一个bool也可以给bool类型赋值

   //e = 12 + 12  // 报错:cannot use 12 + 12 (type untyped int) as type bool in assignment

   t.Log("b:", b)
   t.Log("c:", c)
   t.Log("d:", d) //为赋值默认为false
   t.Log("e:", e)
}  

输出:

 === RUN   TestBoolType
    data_type_test.go:12: 当前时间戳: 1631169712
    data_type_test.go:19: b: false
    data_type_test.go:20: c: true
    data_type_test.go:21: d: false
    data_type_test.go:22: e: false
--- PASS: TestBoolType (0.00s)
PASS  

2. 数字类型

数字类型有很多种,重点说下整数及运算方式:

 package test

import (
   "testing"
   "time"
)

// 加法、减法、乘法、除法、取余、左移、右移、异或 运算
func operation( t *testing.T, a, b int) {
   t.Logf("输入参数:[%d],[%d]", a, b)
   t.Log("加法运算结果:", a + b)
   t.Log("减法运算结果:", a - b)
   t.Log("乘法运算结果:", a * b)
   t.Log("除法运算结果:", a / b)
   t.Log("整除取余结果:", a % b)
   t.Log("左移运算结果:", a << b) // 0010 << 1 -> 0100
   t.Log("右移运算结果:", a >> b) // 0010 >> 1 -> 0001
   t.Log("异或运算结果:", a ^ b)  // 0010 ^ 0001 -> 0011
}

/*
测试整形类型
*/
func TestDataType(t *testing.T) {
   var i, j int
   i, j = 2, 1
   operation(t, i, j)
}  

输出:

 === RUN   TestDataType
    data_type_test.go:44: i:2, j:1
    data_type_test.go:27: 输入参数:[2],[1]
    data_type_test.go:28: 加法运算结果: 3
    data_type_test.go:29: 减法运算结果: 1
    data_type_test.go:30: 乘法运算结果: 2
    data_type_test.go:31: 除法运算结果: 2
    data_type_test.go:32: 整除取余结果: 0
    data_type_test.go:33: 左移运算结果: 4
    data_type_test.go:34: 右移运算结果: 1
    data_type_test.go:35: 异或运算结果: 3
--- PASS: TestDataType (0.00s)
PASS  

以上代码注意点:

  • Golang中 ++ 和 –在以上代码中没有体现,原因是 i++或者i–是语句而非表达式,语句的意思是会对++或–前面的变量进行处理,而不会有任何返回值。所以我们可以在条件语句中使用,改变的是变量指向的地址内存的值。同时没有–i 或者++i这种操作。
  • int和uint型在不同位操作系统所代表的长度是不同的,在32位操作系统上,它们均使用 32 位(4 个字节),在 64 位操作系统上,它们均使用 64 位(8 个字节)

除了int型外,Golang还有下面的数字类型:

 // 有符号整数
int8(-128 -> 127)
int16(-32768 -> 32767)
int32(-2,147,483,648 -> 2,147,483,647)
int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)


// 无符号整数
uint8(0 -> 255)
uint16(0 -> 65,535)
uint32(0 -> 4,294,967,295)
uint64(0 -> 18,446,744,073,709,551,615)

// 浮点型
float32(+- 1e-45 -> +- 3.4 * 1e38)
float64(+- 5 1e-324 -> 107 1e308)

// 复数
Golang 拥有以下复数类型:
complex64 (32 位实数和虚数)
complex128 (64 位实数和虚数)

复数使用 re+imI 来表示,其中 re 代表实数部分, im 代表虚数部分,I 代表根号负 1
var c1 complex64 = 5 + 10i
fmt.Printf("The value is: %v", c1)  // 输出: 5 + 10i  

注意:

整型的默认值和零值为 0,浮点型的默认值和零值为 0.0。默认值表示声明为赋值的变量

在开发过程中大部分情况使用的是int型,int 型是计算速度最快的一种类型

如果使用浮点型时尽量使用float64, 保证精度同时科学计算函数math会需要这个精度

Golang是强类型语言,不支持隐形类型转换。

3. uintptr类型

uintptr 是Golang中的整数类型,能够存储指针值的无符号整数,实际是通过一个uint(无符号整形)来表示地址。

和通用行指针unsafe.Pointer的区别后面在讲, 此处会设计到不安全编程里面的unsafe包。

4. 字符类型

字符在Golang中是通过整数表示的展示形式而已,每个字符都可以通过整数形式来表示:

 package test

import (
   "reflect"
   "testing"
   "time"
)

// 字符类型
func TestString(t *testing.T) {

   // byte
   var s string
   s = "hello go"
   var sb []byte = []byte(s) // 字符串转数组
   var ss string = string(sb) // 数组转字符串

   var s1 byte = 'h'
   var s2 byte = 66
   t.Logf("sb的值%v",sb) // 格式化打印后面会在学习fmt包时详解,当前%v表示默认格式输出
   t.Logf("ss的值%v",ss)
   t.Logf("s1的值%v",s1)
   t.Logf("s2的值%v",s2)

   // rune
   var ch int = '\u0041'
   var ch2 int = '\u03B2'
   var ch3 int = '\U00101234'
   t.Logf("%d - %d - %d\n", ch, ch2, ch3) // %d 打印整形
   t.Logf("%c - %c - %c\n", ch, ch2, ch3) // %c 打印相应Unicode码点所表示的字符
   t.Logf("%X - %X - %X\n", ch, ch2, ch3) // %X 打印十六进制表示,字母形式为大写 A-F
   t.Logf("%U - %U - %U\n", ch, ch2, ch3) // %U 打印Unicode格式:U+1234,等同于 "U+%04X"

   var teststr = "你好啊,go"
   t.Log("通过byte处理字符串", []byte(teststr))
   t.Log("通过rune处理字符串", []rune(teststr))
   // 通过byte和rune处理单字节ascii效果是一样的,但是处理多字节就会不通,
   // 因为rune能处理更大的字节数,因为Go语言中默认是用UTF-8类型,
   // UTF-8类型是三个16进制表示,所以是三字节,输出的结果正好是byte处理的
   // 没三个数据合并成一个。
}  

输出:

 === RUN   TestString
    data_type_test.go:20: sb的值[104 101 108 108 111 32 103 111]
    data_type_test.go:21: ss的值hello go
    data_type_test.go:22: s1的值104
    data_type_test.go:23: s2的值66
    data_type_test.go:29: 65 - 946 - 1053236
    data_type_test.go:30: A - β - 
    data_type_test.go:31: 41 - 3B2 - 101234
    data_type_test.go:32: U+0041 - U+03B2 - U+101234
    data_type_test.go:35: 通过byte处理字符串 [228 189 160 229 165 189 229 149 138 239 188 140 103 111]
    data_type_test.go:36: 通过rune处理字符串 [20320 22909 21834 65292 103 111]
--- PASS: TestString (0.00s)
PASS  

以上代码注意:

byte类型是uint8的别名,byte会表示单字节数据ascii字符,[]byte可以表示字符串,

rune类型是int32的别名,rune用来表示多字节数据unicode或utf-8字符,

Unicode 至少占用 2 个字节,Go会使用int类型或者int16类型来表示,在使用\u前缀表示后面是2字节(长度为4的16进制数),如果前缀为\U则表示后面是4字节(长度为8的16进制数)

0x02 — 字符串

字符串是 UTF-8 字符的一个序列(当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节),字符串在GoLang内存模型中用两个字节长度表示结构,包含一个指向存储的指针,和一个长度数据。

 struct String
{
    byte*   str;
    intgo   len;
};  

需要注意:

字符串是一种值类型,且值不可变,所以多字符串共享同一个存储数据是安全的。

字符串是可进行切分操作str[i:j],切分后会得到一个新的2字长结构,指针字段指向同一个字节序列,长度表示新字符串的长度,所以字符串切分不涉及内存的 重新 分配

字符串类型的零值为指针为nil,len为0的字符串,即空字符串 “”

获取字符串中某个字节的地址的行为是非法的,例如: &s[1],会存在异常:Cannot take the address of ‘s[1]

0x03 — 总结

数据类型是Golang入门的基础,需要搞明白,但是有些不常用的类型比如complex128等可以先不用了解,如果不做数据分析工作应该很少会用到。

相关文章