Go 语言中的数值类型
Go 语言原生支持的数值类型包括整型、浮点型和复数类型,它们适用于不同的场景。
整型
Go 语言的整型,主要用来表示现实世界中整型数量;比如:人的年龄、公司人数等等
Go 语言中分为平台无关整型和平台相关整型两种,它们的区别主要是 CPU 架构或操作系统的字节长度,在 32 位的系统上,int
类型是 32 位的(-231 到 231 - 1);在 64 位的系统上 ,int
类型是 64 位的(-263 到-263-1);如果 int64
在 32 位的系统上,它的极限值也只能是 int32
的取值范围。
平台无关整型和平台相关整型
有符号整型(int8
~ int64
)和无符号整型(uint8
~uint64
)。两者的本质差别在于最高二进制位(bit 位)是否被解释为符号位,这点会影响到无符号整型与有符号整型的取值范围。
-
平台无关整型又分有符号整型和和无符号整型。
有符号整型表示的数值可以为负数、零和正数;比如:
int8
、int16
、int32
、int64
无符号整型表示的数值只能为零和正数;比如:
uint8
、uint16
、uint32
、uint64
-
平台相关型整数
int
、uint
、uintptr
;byte
其实等价与uint8
类型,可以理解为uint8
类型的别名,用于定义一个字节,所以字节类型也属于整型
整型的溢出问题
无论哪种整型,都有它的取值范围,也就是有它可以表示的值边界。如果这个整型因为参与某个运算,导致结果超出了这个整型的值边界,我们就说发生了整型溢出的问题。
package main
import "fmt"
func main() {
var s int8 = 127
s += 1
fmt.Println(s) // 预期128,实际结果-128
var u uint8 = 1
u -= 2
fmt.Println(u) // 预期-1,实际结果255
}
这个问题最容易发生在循环语句的结束时的条件判断中;无论无符号整型,还是有符号整型都存在溢出的问题,所以我们要十分小心地选择参与循环语句结束判断的整型变量类型,以及与之比较的边界值。
字面值与格式化
早期 Go 版本支持十进制、八进制、十六进制的数值字面值形式:
a := 53 // 十进制
b := 0700 // 八进制,以"0"为前缀
c := 0xaabbcc // 十六进制,以"0x"为前缀
d := 0Xddeeff // 十六进制,以"0X"为前缀
Go 1.13 版本中,Go 又增加了对二进制字面值的支持和两种八进制字面值的形式;
a := 0b10000001 // 二进制,以"0b"为前缀
b := 0B10000001 // 二进制,以"0B"为前缀
c := 0o700 // 八进制,以"0o"为前缀
d := 0O700 // 八进制,以"0O"为前缀
当然,也支持使用 _ 来分割数字
package main
import "fmt"
func main() {
bignumber := 42_433_432
fmt.Println("bignumber:", bignumber) // bignumber: 42433432
}
为提升字面值的可读性,Go 1.13 版本还支持在字面值中增加数字分隔符“_”,分隔符可以用来将数字分组以提高可读性。
Go 1.13 中增加的二进制字面值以及数字分隔符,只在 go.mod 中的 go version 指示字段为 Go 1.13 以及以后版本的时候,才会生效,否则编译器会报错。
通过标准库 fmt 包的格式化输出函数将一个整型变量输出位不同进制的形式
package main
import "fmt"
func main() {
var a int8 = 59
fmt.Printf("%b\n", a) //输出二进制:111011
fmt.Printf("%d\n", a) //输出十进制:59
fmt.Printf("%o\n", a) //输出八进制:73
fmt.Printf("%O\n", a) //输出八进制(带0o前缀):0o73
fmt.Printf("%x\n", a) //输出十六进制(小写):3b
fmt.Printf("%X\n", a) //输出十六进制(大写):3B
}
常用类型转换方法
-
整数转浮点数
package main func main(){ var a int = 10 // 字面量转换方式 fmt.Printf("%f\n", float64(a)) // 10.000000 // 使用 strconv 包的 ParseFloat 函数转换 var b float64 b, _ = strconv.ParseFloat(strconv.Itoa(a), 64) fmt.Printf("%f\n", b) // 10.000000 // 使用字符串格式化函数 fmt.Sprintf 将整数格式化为带有小数点的字符串,然后使用 strconv 包中的 ParseFloat 函数将字符串转换为浮点数 formattedString := fmt.Sprintf("%.1f", float64(a)) b, _ = strconv.ParseFloat(formattedString, 64) fmt.Println("b TypeOf:", reflect.TypeOf(b)) // b TypeOf: float64 }
-
整数转字符串
package main import "fmt" func main(){ var a int = 10 str := strconv.Itoa(a) fmt.Printf("str: %s, type of: %s\n", str, reflect.TypeOf(str)) // str: 10, type of: string str = fmt.Sprintf("%d", a) fmt.Printf("str: %s, type of: %s\n", str, reflect.TypeOf(str)) // str: 10, type of: string str = strconv.FormatInt(int64(a), 10) fmt.Printf("str: %s, type of: %s\n", str, reflect.TypeOf(str)) // str: 10, type of: string }
-
整数转布尔
关系运算符、相等或不相等
package main import ( "fmt" ) func main() { var a int = 10 fmt.Printf("a: %v\n", a > 10) // a: false fmt.Printf("a: %v\n", a < 10) // a: false fmt.Printf("a: %v\n", a >= 10) // a: true fmt.Printf("a: %v\n", a <= 10) // a: true fmt.Printf("a: %v\n", a == 10) // a: true fmt.Printf("a: %v\n", a != 10) // a: false }
浮点型
浮点数代表现实中的小数;Go 语言中提供了两种精度的浮点数,分别是float32
和 float64
;无论是 float32
还是float64
,他们的变量的默认值都是 0.0
字面值与格式化输出
-
fmt
包也提供了针对浮点数的格式化输出。我们最常使用的格式化输出形式是%f
。通过%f
,我们可以输出浮点数最直观的原值形式:var f float64 = 123.45678 fmt.Printf("%f\n", f) // 123.456780
-
%e
输出的是十进制的科学计数法形式,而%x
输出的则是十六进制的科学计数法形式:var f float64 = 123.45678 fmt.Printf("%e\n", f) // 1.234568e+02 fmt.Printf("%x\n", f) // 0x1.edd3be22e5de1p+06
常用方法
-
浮点数转字符串
package main import ( "fmt" "reflect" "strconv" ) func main() { var a float64 = 10.0 strNum := strconv.FormatFloat(a, 'f', -1, 64) fmt.Printf("strNum: %s, type of: %s\n", strNum, reflect.TypeOf(strNum)) // strNum: 10, type of: string }
-
浮点数转整数
package main import ( "fmt" "reflect" ) func main() { var f float64 = 3.14 // 使用类型转换将浮点数转换为整数;通过将浮点数直接赋值给整数类型的变量,Go语言会自动进行类型转换,将浮点数的小数部分截断,得到整数部分。请注意,这种类型转换会丢失浮点数的小数部分 b := int(f) fmt.Printf("str Num: %d, type of: %s\n", b, reflect.TypeOf(b)) // str Num: 3, type of: int // 使用 math 包的函数将浮点数转换为整数 i := int(math.Round(f)) fmt.Printf("i: %d, type of: %s\n", i, reflect.TypeOf(i)) // i: 3, type of: int }
-
浮点数转布尔
相等运算符、相等、不相等
package main import ( "fmt" ) // ? 待分析 func main() { var f1 float32 = 16777216.0 var f2 float32 = 16777217.0 fmt.Println(f1 == f2) // true }
复数类型
数学课本上将形如 z=a+bi(a、b 均为实数,a 称为实部,b 称为虚部)
的数称为复数。
复数字面值的三种表示方法
-
字面值初始化
package main import "fmt" func main() { var c = 5 + 6i var d = 0o123 + .12345e+5i fmt.Println("c:", c) // 5 + 6i fmt.Println("d:", d) // 83+12345i }
-
使用
complex
package main import "fmt" func main() { var c = complex(5, 6) var d = complex(0o123, .12345e+5) fmt.Println("c:", c) // 5 + 6i fmt.Println("d:", d) // 83+12345i }
-
使用
real
和imag
获取一复数的实部与虚部,返回一个浮点类型package main import "fmt" func main() { var c = complex(5, 6) // 5 + 6i r := real(c) // 5.000000 i := imag(c) // 6.000000 fmt.Println("c:", c) // c: 5 + 6i fmt.Println("d:", r) // d: 5 fmt.Println("i:", i) // i: 6 }
自定义数值类型(类型别名)
-
通过 type 关键字基于原生数值类型来声明一个新类型
type MyInt int32
-
MyInt 与 int32 的值无法直接让他们相互赋值,或者是把他们放在同一个运算中直接计算,否则编译器就会报错;解决方案———显示转换