数据类型
语言类型
强类型语言
强类型语言又叫做静态语言,类型是在编译阶段确认,并且不能随意修改。
Go是典型的强类型语言。
弱类型语言
弱类型语言与叫做动态语言,运行时进行类型推断,并且可以进行类型转换。
Go数据类型
基本数据类型
- 布尔类型。
- 数值类型(整型、浮点型、复数、指针)。
- 字符串类型
派生数据类型
- 指针
*pointer - 数组
Array - 结构体
struct - 通道
channel - 切片
slice - 接口
interface - 映射
map - 函数
func
类型分类
值类型
- 布尔类型、数值类型、字符串类型、数组类型、结构体类型。
- 值类型一般由内存中的栈内存进行空间分配,并且固定内存空间大小。
package main
import "fmt"
func main() {
var x int = 1
var y int = x
fmt.Println(x, y) // 1 1
}
/**
标识符 地址 内存空间
x 0x0001 1
y 0x0002 1
*/
以上过程如下:
- 声明变量
x。 - 将
1赋值给x。 - 声明变量
y。 - 将
x存储的值1拷贝一份。 - 将拷贝的
1赋值给变量y。
引用类型
- Go语言中引用类型包含指针、通道、切片、接口、映射、函数。
- 变量对应的栈内存空间为堆内存空间的一个地址,通过这个地址来访问堆内存对应地址的空间,从空间中取出值。
- 引用类型引用的是堆内存空间的地址,如果多个变量引用同一个地址,那么它们共享这些值。
- 引用类型一般对于内存空间的分配是动态的。
数值类型
整型
整型的默认类型是int,占用字节数取决于操作系统,可认为int泛指整型。
| 类型名 | 字节数 | 二进制存储位数 | 取值范围 | 数值范围 |
|---|---|---|---|---|
int | 4 | 32 | -231 ~ 231 - 1 | -2147483648 ~ 2147483647 |
int | 8 | 64 | -263 ~ 263 - 1 | - |
int8 | 1 | 8 | -27 ~ 27 - 1 | -128 ~ 127 |
int16 | 2 | 16 | -215 ~ 215 - 1 | -32768 ~ 32767 |
int32 | 4 | 32 | -231 ~ 231 - 1 | -2147483648 ~ 2147483647 |
int64 | 8 | 64 | -263 ~ 263 - 1 | - |
package main
func main() {
var (
a int = 1
b int8 = 127
c int16 = 32767
d int32 = 2147483647
)
}
无符号类型
有符号(可表示正负数)的整数类型:int、int8、int16、int32、int64。
无符号(从0开始的取值范围)的整数类型:uint、uint8、uint16、uint32、uint64、uintptr。
- 有符号和无符号的取值范围不同。
- 有符号内存占用略大于无符号。
- 使用场景不同。
uintptr占用4或8个字节,无符号整型,用于存储指针,跟C语言交互。
浮点型
浮点型的默认类型是float64。
| 类型名 | 字节数 | 二进制存储位数 | 取值范围 |
|---|---|---|---|
float32 | 4 | 32 | -3.4E38 ~ -1.4E-45, 1.4E-45 ~ 3.4E38 |
float64 | 8 | 64 | -1.7E308 ~ -4.9E-324, 4.9E-324 ~ 1.7E308 |
package main
func main() {
var (
a float32 = 3.14
b float64 = 3.1415926
)
}
复数
- 复数一般用于科学计算。
complex64两个float32,一个表示32位实部,一个表示32位虚部。complex128两个float64,一个表示64位实部,一个表示64位虚部。
byte
byte是用来存放字符编码的类型,可以表示ASCII码的一个字符。byte相当于uint8,表示范围是0 ~ 255。- 字符要使用单引号,字符存储本质上是字符编码的存储。
- ASCII码本质上就是一个字符对应一个整数的字符和数字之间的交换。
byte字符的存储就是对字符对应的ASCII码进行存储。byte类型可用来缩值范围,也可以做数学运算。
package main
import "fmt"
func main() {
var (
a byte = 'a'
b uint8 = 97
)
fmt.Println(a, b) // 97 97
}
声明时,byte需要显式地指定,由于字符的默认类型是int32,因此类型推断并不好使:
package main
import "fmt"
func main() {
// var a byte = 'a'
// var a rune
var a = 'a'
fmt.Println(a)
}
ASCII码整表如下:

rune
rune也是用来存放字符编码的类型,相当于int32。rune可存储更多字符的编码,包含所有unicode码对应的字符,unicode本质就是对ASCII的扩展。rune存储的是字符对应的编码,因此本质也是存储数字。- 在Go语言中,不存在
char类型,而是把所有的字符看做是一个数字,只要这个数字能对应上ASCII或unicode码就能输出对应字符。
Unicode是一个字符编码标准,为世界上几乎所有的字符集分配了唯一的数字码点。Unicode的编码范围是从U+0000到U+10FFFF,理论上共计1114112个码点。
Unicode的码点分为17个平面,每个平面有65536(2^16)个码点。其中,基本多文本平面(BMP,也称为平面0)包含了最常用的字符,范围是U+0000到U+FFFF。
由于Unicode码的最大范围是110多万,使用int32完全可以满足其存储范围,因此没必要使用uint32。
中文字符的Unicode码主要集中在平面0,范围通常是U+4E00到U+9FFF,大约20992个汉字。
package main
import "fmt"
func main() {
var ch rune = '我'
fmt.Println(ch) // 25105
fmt.Printf("%c", ch) // '我'
// var ch1 rune
var c = '中'
// var a rune
a := '你'
}
布尔类型
布尔类型只有两个值true和false,通常表示:
- 是与非
- 真与假
- 对与错
- 成立与不成立
package main
import "fmt"
func main() {
var a bool
a = false
var b = true
c := false
fmt.Println(a, b, c)
}
字符串类型
- 存储字符集合的类型。
- 值要用双引号。
- 在Go语言中,一个中文字符占3个字节。
package main
import "fmt"
func main() {
var name string
name = "Tom"
var a = "hello "
b := "world"
fullString := name + "," + a + b
stringLen := len(fullString)
fmt.Println(name, a, b, fullString, stringLen)
}
数值间转换
- 数值类型之间可以相互转换,如整型转浮点型、浮点型转整型、有符号整型转无符号整型等。
- 浮点型转整型通常会忽略小数点,导致精度丢失。
var a = 123
var b = float32(a)
var c = 3.1415
var d = int32(c)
var e = -123
// 256 - 123 = 133
var f = uint(e)
字符串转换
字符串相关转换操作需要使用到strconv包中的方法。
string
使用string转换整数为一个字符串时,结果表示对应的unicode码的字符。
package main
import (
"fmt"
)
func main() {
var a = 97
var res = string(a)
fmt.Println(res) // 'a'
}
strconv.Atoi
func Atoi(s string) (int, error) { }
strconv.Atoi用于string转int。- 返回两个值,转换后的结果及错误原因。
- 转换过程有可能不成功。
package main
import (
"fmt"
"strconv"
)
func main() {
var str = "123"
a, err := strconv.Atoi(str)
if err != nil {
fmt.Println(err)
}
fmt.Println(a)
}
strconv.Itoa
func Itoa(i int) string { }
int转string。- 数字必然能转成字符串,因此无需抛出错误。
package main
import (
"fmt"
"strconv"
)
func main() {
var num = 123
a := strconv.Itoa(num)
fmt.Println(a)
}
strconv.ParseInt
func ParseInt(
s string,
base int,
bitSize int
) (i int64, err error) {
// code
}
string转int。base代表进制,bitSize代表位数。- 有可能转换不成功。
package main
import (
"fmt"
"strconv"
)
func main() {
// 把 "100" 看作二进制进行十进制解析,最终输出十进制
f, err := strconv.ParseInt("100", 2, 64)
if err != nil {
fmt.Println(err)
}
fmt.Println(f)
}
如果string转int中涉及到进制,则使用strconv.ParseInt,否则可直接使用strconv.Atoi。
strconv.ParseFloat
func ParseFloat(
s string,
bitSize int
) (float64, error) {
// code
}
string转float- 返回两个值,转换结果及错误,有可能转换失败。
biteSize表示转换时使用32或64位,返回值是float64类型。
package main
import (
"fmt"
"strconv"
)
func main() {
var str = "3.1415"
a, err := strconv.ParseFloat(str, 64)
if err != nil {
fmt.Println(err)
}
fmt.Println(a)
}
strconv.ParseBool
func ParseBool(str string) (bool, error) {
string转bool- 参数可以是
"1"、"0"、"false"、"true",其它值都会解析错误。
package main
import (
"fmt"
"strconv"
)
func main() {
i, err := strconv.ParseBool("false")
if err != nil {
fmt.Println(err)
}
fmt.Println(i)
}
strconv.FormatInt
func FormatInt(i int64, base int) string { }
- 将十进制转换成给定的(
base)进制字符串。 - 此过程必定会转成成功,因此无需抛出错误。
package main
import (
"fmt"
"strconv"
)
func main() {
// 将100转换成二进制并输出该字符串
str := strconv.FormatInt(100, 2)
fmt.Println(str)
}
strconv.FormatFloat
func FormatFloat(
f float64,
fmt byte,
prec,
bitSize int
) string {}
float转string。- 接受四个参数:
fflaoat64类型的浮点数。fmt格式化类型,一般为f。prec输出精度,即小数点后保留位数,会自动四舍五入,如果是-1,则保留参数f的原有位数。bitSize32或64位数。
package main
import (
"fmt"
"strconv"
)
func main() {
str := strconv.FormatFloat(3.1415926, 'f', 4, 64)
fmt.Println(str)
}
strconv.FormatBool
func FormatBool(b bool) string { }
bool转string- 参数仅接收
bool类型。
package main
import (
"fmt"
"strconv"
)
func main() {
a := strconv.FormatBool(false)
fmt.Println(a)
}
自定义类型
给一种新的类型赋予另一种已有类型的特性,让类型更加的语义化,其不能用做默认类型。
如下,将float64的特点给到类型typeAmount,并不代表两者是同一类型,它们仍然是不同的类型,因此不能直接进行相关操作,需要进行类型转换。
package main
func main() {
type typeAmount float64
var amount typeAmount = 1000.2343
var newAmount = 100.23
// invalid operation: amount - newAmount (mismatched types typeAmount and float64)
// num := amount - newAmount
num := float64(amount) - newAmount
// num := amount - typeAmount(newAmount)
fmt.Println(num)
}
获取类型
reflect包下的Typeof方法可用来获取变量的类型:
package main
import (
"fmt"
"reflect"
)
type myType float64
func main() {
a := true
b := 123
c := "abcd"
d := 3.14
var e myType = 123
fmt.Println(reflect.TypeOf(a)) // bool
fmt.Println(reflect.TypeOf(b)) // int
fmt.Println(reflect.TypeOf(c)) // string
fmt.Println(reflect.TypeOf(d)) // float64
fmt.Println(reflect.TypeOf(e)) // myType
}
还有一种是通过reflect包的Valueof方法下的Kind方法:
func main() {
fmt.Println(reflect.ValueOf(a).Kind()) // bool
fmt.Println(reflect.ValueOf(b).Kind()) // int
fmt.Println(reflect.ValueOf(c).Kind()) // string
fmt.Println(reflect.ValueOf(d).Kind()) // float64
}
类型断言
类型断言提供了接口值的底层具体值的访问。
v := i.(T)
这个语句断言接口值i持有具体类型T,并将底层的T值赋给变量v。如果i不持有T,该语句将触发panic。
为了测试一个接口值是否持有特定类型,类型断言可以返回两个值:底层的值和一个布尔值,用于报告断言是否成功。
package main
func mauin() {
stuInfo := map[string]interface{}{
"name": "Tom",
"age": 12,
}
name, nameOk := stuInfo["name"].(string)
age, ageOk := stuInfo["age"].(string)
fmt.Println(name, nameOk)
fmt.Println(age, ageOk)
}
如果断言成功,则返回底层值和true,否则将返回断言类型的零值和false。