【Go】--数据类型
Go 语言数据类型与精度详解
基本数据类型
1. 整数类型
有符号整数
var a int8 // 1字节,范围:-128 到 127
var b int16 // 2字节,范围:-32768 到 32767
var c int32 // 4字节,范围:-2147483648 到 2147483647
var d int64 // 8字节,范围:-9223372036854775808 到 9223372036854775807
var e int // 平台相关,32位系统为int32,64位系统为int64
无符号整数
var a uint8 // 1字节,范围:0 到 255
var b uint16 // 2字节,范围:0 到 65535
var c uint32 // 4字节,范围:0 到 4294967295
var d uint64 // 8字节,范围:0 到 18446744073709551615
var e uint // 平台相关
var f byte // uint8 的别名
var g rune // int32 的别名,表示Unicode码点
2. 浮点数类型
var a float32 // 4字节,单精度浮点数
var b float64 // 8字节,双精度浮点数(默认类型)
var c complex64 // 8字节,复数,实部和虚部都是float32
var d complex128 // 16字节,复数,实部和虚部都是float64
3. 布尔类型
var a bool = true
var b bool = false
4. 字符串类型
var s string = "Hello, World!"
精度
整数精度
package mainimport ("fmt""math""unsafe"
)func main() {// 整数类型的精度和范围fmt.Printf("int8 范围: %d 到 %d\n", math.MinInt8, math.MaxInt8)fmt.Printf("int16 范围: %d 到 %d\n", math.MinInt16, math.MaxInt16)fmt.Printf("int32 范围: %d 到 %d\n", math.MinInt32, math.MaxInt32)fmt.Printf("int64 范围: %d 到 %d\n", math.MinInt64, math.MaxInt64)fmt.Printf("uint8 范围: 0 到 %d\n", math.MaxUint8)fmt.Printf("uint16 范围: 0 到 %d\n", math.MaxUint16)fmt.Printf("uint32 范围: 0 到 %d\n", math.MaxUint32)fmt.Printf("uint64 范围: 0 到 %d\n", uint64(math.MaxUint64))// 大小验证var i intfmt.Printf("int 大小: %d 字节\n", unsafe.Sizeof(i))
}
浮点数精度
package mainimport ("fmt""math"
)func floatPrecisionDemo() {// float32 精度(约6-7位十进制数)var f32 float32 = 123.456789fmt.Printf("float32 值: %.10f\n", f32) // 输出: 123.4567871094// float64 精度(约15-16位十进制数)var f64 float64 = 123.4567890123456789fmt.Printf("float64 值: %.20f\n", f64) // 输出: 123.4567890123456800// 精度测试fmt.Printf("float32 最大正数: %e\n", math.MaxFloat32)fmt.Printf("float64 最大正数: %e\n", math.MaxFloat64)fmt.Printf("float32 最小正数: %e\n", math.SmallestNonzeroFloat32)fmt.Printf("float64 最小正数: %e\n", math.SmallestNonzeroFloat64)// 浮点数比较(由于精度问题,不要直接比较)a := 0.1b := 0.2c := 0.3// 错误的比较方式fmt.Printf("直接比较: %v\n", a+b == c) // 可能输出 false// 正确的比较方式fmt.Printf("容差比较: %v\n", math.Abs((a+b)-c) < 1e-9) // 输出 true
}
复数精度
func complexPrecisionDemo() {// complex64 精度var c1 complex64 = 1.23456789 + 9.87654321ifmt.Printf("complex64: %.10f + %.10fi\n", real(c1), imag(c1))// complex128 精度var c2 complex128 = 1.2345678901234567 + 9.8765432109876543ifmt.Printf("complex128: %.20f + %.20fi\n", real(c2), imag(c2))
}
类型转换与精度损失
显式类型转换
package mainimport "fmt"func typeConversionDemo() {// 整数类型转换var big int64 = 1234567890var small int32 = int32(big) // 显式转换// 可能导致精度损失的情况var tooBig int64 = 9999999999var converted int32 = int32(tooBig) // 溢出,值会改变fmt.Printf("原始值: %d, 转换后: %d\n", tooBig, converted)// 浮点数转整数(截断小数部分)var f float64 = 123.987var i int = int(f) // 123,小数部分被截断fmt.Printf("浮点数: %f, 转整数: %d\n", f, i)// 整数转浮点数var num int = 123456789var f32 float32 = float32(num)var f64 float64 = float64(num)fmt.Printf("整数: %d, float32: %f, float64: %f\n", num, f32, f64)
}
精度损失示例
func precisionLossDemo() {// float32 到 float64 转换f32 := float32(1.23456789)f64 := float64(f32)fmt.Printf("原始 float32: %.8f\n", f32)fmt.Printf("转换到 float64: %.8f\n", f64)// 大整数转浮点数的精度损失bigInt := int64(9007199254740993) // 2^53 + 1bigFloat := float64(bigInt)fmt.Printf("大整数: %d\n", bigInt)fmt.Printf("转浮点数: %.0f\n", bigFloat)fmt.Printf("是否相等: %v\n", int64(bigFloat) == bigInt)
}
精度考虑
-
选择合适的数据类型:
- 一般情况使用
int
和float64
- 内存敏感场景使用特定大小的类型
- 金融计算考虑使用整数或
math/big
包
- 一般情况使用
-
避免隐式类型转换:
- Go 要求显式类型转换,这有助于避免意外行为
-
注意溢出和精度损失:
- 在类型转换时检查可能的溢出
- 浮点数比较使用容差而非直接相等
-
使用标准库函数:
import "math"// 安全的浮点数比较 func almostEqual(a, b, tolerance float64) bool {return math.Abs(a-b) < tolerance }
金融计算
package mainimport ("fmt""math/big"
)func financialCalculation() {// 对于金融计算,使用整数表示最小单位(如分)type Money int64 // 以分为单位var price Money = 1999 // 19.99元var quantity int = 3total := price * Money(quantity)fmt.Printf("总价: %.2f 元\n", float64(total)/100.0)// 或者使用 big.Rat 进行精确计算priceRat := big.NewRat(1999, 100) // 19.99quantityRat := big.NewRat(3, 1)totalRat := new(big.Rat).Mul(priceRat, quantityRat)fmt.Printf("精确总价: %s 元\n", totalRat.FloatString(2))
}
科学计算
func scientificCalculation() {// 对于需要高精度的科学计算const preciseValue float64 = 3.14159265358979323846// 使用 float64 获得更高精度circumference := 2 * preciseValue * 10.0area := preciseValue * 10.0 * 10.0fmt.Printf("周长: %.15f\n", circumference)fmt.Printf("面积: %.15f\n", area)// 避免累积误差var sum float64for i := 0; i < 1000; i++ {sum += 0.1}fmt.Printf("累加 1000 次 0.1: %f\n", sum) // 不是精确的 100.0fmt.Printf("误差: %e\n", sum-100.0)
}