目录
介绍
Go是一种强类型的静态编译语言,类型是高级语言的基础。Go语言内置了7类基本数据类型,包括了20个具体的子类型。
布尔类型
布尔类型的关键字是bool,布尔类型只有两个值:true和false。true和false是Go内置的两个预声明标识符。
初始化
使用var关键字初始化布尔变量:
var demo bool
在函数内部也可以直接赋值,编译器会自行推断:
ok := true
赋值
直接使用true或false赋值:
var success bool
success = true
使用比较表达式或逻辑表达式赋值。赋值的结果就是表达式的逻辑结果值:
x := 1
y := 3
var success bool
success = x > y // false
默认值
声明的bool变量如不指定初始化值,则默认为false。
package main
import "fmt"
func main() {
var demo bool
fmt.Println(demo)
// output: false
}
整型
Go内置了12种整数类型,分为有符号整型和无符号整型两大类:
整数类型 | 备注 | |
---|---|---|
有符号 | int | 所占用的字节数与运行机器的CPU相关。在32位机器中,大小为4字节;在64位机器中,大小为8字节 |
int8 | 占用一个字节存储(8位),范围是-128 ~ 127 | |
int16 | 占用两个字节存储(16位),范围是-32768 ~ 32767 | |
int32 | 占用四个字节存储(32位),范围是-2147483648 ~ 2147483647 | |
int64 | 占用八个字节存储(64位),范围是-9223372036854775808 ~ 9223372036854775807 | |
无符号 | uint | 所占用的字节数与运行机器的CPU相关。在32位机器中,大小为4字节;在64位机器中,大小为8字节 |
uint8 | 占用一个字节存储(即8位),范围是0 ~ 255 | |
uint16 | 占用两个字节存储(16位),范围是0 ~ 65535 | |
uint32 | 占用四个字节存储(32位),范围是0 ~ 4294967295 | |
uint64 | 占用八个字节存储(64位),范围是0 ~ 18446744073709551615 | |
uintptr | 一个无符号整数类型 | |
byte | byte类型是uint8的别名 |
byte和uint8
byte是uint8的别名,两者底层结构相同。因此byte变量和uint8变量无需进行类型转换:
package main
import "fmt"
func main() {
var number1 uint8 = 23
var number2 byte
number2 = number1
fmt.Println(number2)
// output: 23
}
类型转换
除别名外,不同类型的整型必须进行强制类型转换,就算是底层结构相同的不同类型,也必须进行强制类型转换。例如在64位的机器中,int和int64的底层结构是一致的,但还是要进行强制类型转换,而不能直接赋值。
package main
import "fmt"
type myInt int
func main() {
var number1 int64 = 3
var number2 int
var number3 myInt
number2 = int(number1)
number3 = myInt(number2)
fmt.Println(number1, number2, number3)
// output: 3, 3, 3
}
支持的操作
整型支持算术运算和位操作,算术表达式和位操作表达式的结果还是整型。
package main
import "fmt"
func main() {
var a int = (1 + 2) * 3
var b int32 = 1000 >> 2
fmt.Println(a, b)
// output: 9, 250
}
浮点型
浮点型用于表示包含小数点的数据,Go语言内置两种浮点数类型,分别是float32和float64。其中浮点数字面量被自动推断为float64。
package main
import "fmt"
func main() {
var number1 = 3.14
number2 := 1.23
var number3 float32 = 3.12
var number4 float64 = 23.567
fmt.Printf("%T, %T, %T, %T\n", number1, number2, number3, number4)
// output: float64, float64, float32, float64
}
精度
一个float32可以提供大约6个十进制精度,而float64可以提供大约15个十进制精度,因此优先使用float64类型。
数值范围
可以使用标准库中的常量math.MaxFloat32和math.MaxFloat64获取到float32和float64的最大值:
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.MaxFloat32)
// output: 3.4028234663852886e+38
fmt.Println(math.MaxFloat64)
// output: 1.7976931348623157e+308
}
类型 | 最大值 | 最小值 |
float32 | 3.4028234663852886e+38 | 1.4e-45 |
float64 | 1.7976931348623157e+308 | 4.9e-324 |
浮点型的比较
在计算机中很难进行浮点数的精确表示和存储,因此两个浮点数之间不应该使用 == 和 != 进行比较操作。高精度的科学计算可以使用math标准库来完成。
复数
Go语言内置了两种复数类型,分别是complex64和complex128。复数在计算机中使用两个浮点数来表示,一个表示实部,另一个表示虚部。其中complex64由两个float32构成,complex128由两个float64构成。复数的字面量表示和数学表示法一致,复数字面量默认类型是complex128。
package main
import "fmt"
func main() {
number := 3.1 + 6i
fmt.Printf("%v, %T\n", number, number)
// output: (3.1+6i), complex128
}
构造复数
可以使用内置函数complex来构造复数。
package main
import "fmt"
func main() {
number := complex(2.1, 3)
fmt.Printf("%v, %T\n", number, number)
// output: (2.1+3i), complex128
number2 := complex(float32(2.1), 3)
fmt.Printf("%v, %T\n", number2, number2)
// output: (2.1+3i), complex64
}
获取实部和虚部
使用内置函数real和imag可以获取复数的实部和虚部:
package main
import "fmt"
func main() {
number1 := complex128(23 + 6i)
real1 := real(number1)
img1 := imag(number1)
fmt.Printf("real: %v, real type: %T, image: %v, image type: %T\n", real1, real1, img1, img1)
// output: real: 23, real type: float64, image: 6, image type: float64
number2 := complex64(23 + 6i)
real2 := real(number2)
img2 := imag(number2)
fmt.Printf("real: %v, real type: %T, image: %v, image type: %T\n", real2, real2, img2, img2)
// output: real: 23, real type: float32, image: 6, image type: float32
}
字符串
Go语言将字符串作为一种原生的基本数据类型。字符串是一个不可修改的数据类型。它的底层结构如下:
type stringStruct struct {
str unsafe.Pointer // 指向底层字节数组的指针
len int // 字节数组长度
}
初始化
字符串的初始化可以使用字符串字面量:
var s = "hello world"
访问内部成员
字符串是常量,可以通过索引访问其字节单元。但不能修改某个字节的值。
package main
import "fmt"
func main() {
var s = "hello world"
fmt.Printf("%v, %T\n", s[0], s[0])
// output: 104, uint8
s[0] = "H"
// panic: cannot assign to s[0] (strings are immutable)
}
字符串切片
基于字符串创建的切片和原字符串指向相同的底层数组,一样不可修改。对字符串的切片操作返回的结果仍然是字符串string,而不是slice。
package main
import (
"fmt"
)
func main() {
sentence := "hello world!"
sub1 := sentence[0:4]
sub2 := sentence[:4]
fmt.Printf("sub1: %s, %T\n", sub1, sub1)
// output: sub1: hell, string
fmt.Printf("sub2: %s, %T\n", sub2, sub2)
// output: sub2: hell, string
}
与切片的转换
使用类型转换可以将字符串直接转换为byte切片和rune切片。但注意当字符串数据量很大时,使用该方法要慎重,因为转换过程中需要全部复制字符串的内容。
使用强制类型转换也可以将[]byte与[]rune转换为字符串。
package main
import "fmt"
func main() {
var s = "hello world"
// string to []byte
bytes := []byte(s)
fmt.Println(bytes)
// output: [104 101 108 108 111 32 119 111 114 108 100]
// string to []rune
runes := []rune(s)
fmt.Println(runes)
// output: [104 101 108 108 111 32 119 111 114 108 100]
// []byte to string
s1 := string(bytes)
fmt.Println(s1)
// output: hello world
// []rune to string
s2 := string(runes)
fmt.Println(s2)
// output: hello world
}
获取字符串长度
内置的len函数可以获取字符串长度:
package main
import "fmt"
func main() {
sentence := "Hello"
fmt.Println(len(sentence))
// output: 5
}
遍历
字符串的遍历与切片类似,使用range遍历时返回的是一个int类型表示下标和int32类型表示字符的Unicode码:
package main
import "fmt"
func main() {
demo := "hi"
for index, character := range demo {
fmt.Printf("index: %T, %v; character: %T, %v\n", index, index, character,character)
}
// outputs:
// index: int, 0; character: int32, 104
// index: int, 1; character: int32, 105
}
还有更常规一些的遍历方式,遍历下标,并通过下标访问字符串中的每个成员:
package main
import "fmt"
func main() {
demo := "abc"
for i := 0; i < len(demo); i++ {
fmt.Printf("%c", demo[i])
}
// output: abc
}
拼接
使用“+”可以拼接字符串:
package main
import "fmt"
func main() {
s1 := "abc"
s2 := "def"
result := s1 + s2
fmt.Println(result)
// output: adcdef
}
byte & rune
Go内置两种字符类型:一种是byte的字节类型(byte也是uint8的别名),另一种是表示Unicode编码的字符rune。rune在Go的内部是int32类型的别名,占用4个字节。