#Go Type Conversion
Type conversion is an important concept in programming, and Go provides several ways to convert between types. This chapter covers explicit type conversion, type assertions, string conversion, and more.
#📋 Type Conversion Basics
#Explicit Type Conversion
Go does not support implicit type conversion; all conversions must be explicit.
package main
import "fmt"
func main() {
// 数值类型转换
var i int = 42
var f float64 = float64(i) // int 转 float64
var u uint = uint(i) // int 转 uint
fmt.Printf("int: %d, float64: %.2f, uint: %d\n", i, f, u)
// 精度可能丢失的转换
var bigFloat float64 = 123.456
var smallInt int = int(bigFloat) // 小数部分被截断
fmt.Printf("float64: %.3f -> int: %d\n", bigFloat, smallInt)
// 不同大小整数之间的转换
var big int64 = 1000000
var small int32 = int32(big)
fmt.Printf("int64: %d -> int32: %d\n", big, small)
// 字符和数字的转换
var char rune = 'A'
var ascii int = int(char)
var backToChar rune = rune(ascii)
fmt.Printf("字符: %c, ASCII: %d, 转回字符: %c\n", char, ascii, backToChar)
}#Type Conversion Rules
package main
import "fmt"
func main() {
fmt.Println("=== 数值类型转换规则 ===")
// 整数类型之间的转换
var a int8 = 127
var b int16 = int16(a)
var c int32 = int32(b)
var d int64 = int64(c)
fmt.Printf("int8(%d) -> int16(%d) -> int32(%d) -> int64(%d)\n", a, b, c, d)
// 浮点数精度转换
var f64 float64 = 3.141592653589793
var f32 float32 = float32(f64) // 精度降低
var backF64 float64 = float64(f32)
fmt.Printf("原始 float64: %.15f\n", f64)
fmt.Printf("转为 float32: %.15f\n", f32)
fmt.Printf("转回 float64: %.15f\n", backF64)
// 有符号和无符号转换
var signed int = -42
var unsigned uint = uint(signed) // 可能产生意外结果
fmt.Printf("有符号: %d -> 无符号: %d\n", signed, unsigned)
// 布尔值转换(需要手动处理)
var flag bool = true
var intFlag int
if flag {
intFlag = 1
} else {
intFlag = 0
}
fmt.Printf("布尔值: %v -> 整数: %d\n", flag, intFlag)
}#🔤 String Type Conversion
#Using the strconv Package
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Println("=== 字符串与数字转换 ===")
// 字符串转整数
str1 := "123"
if num1, err := strconv.Atoi(str1); err == nil {
fmt.Printf("字符串 '%s' -> 整数: %d\n", str1, num1)
} else {
fmt.Printf("转换失败: %v\n", err)
}
// 整数转字符串
num2 := 456
str2 := strconv.Itoa(num2)
fmt.Printf("整数 %d -> 字符串: '%s'\n", num2, str2)
// 字符串转浮点数
str3 := "3.14159"
if float1, err := strconv.ParseFloat(str3, 64); err == nil {
fmt.Printf("字符串 '%s' -> 浮点数: %.5f\n", str3, float1)
}
// 浮点数转字符串
float2 := 2.71828
str4 := strconv.FormatFloat(float2, 'f', 5, 64)
fmt.Printf("浮点数 %.5f -> 字符串: '%s'\n", float2, str4)
// 字符串转布尔值
str5 := "true"
if bool1, err := strconv.ParseBool(str5); err == nil {
fmt.Printf("字符串 '%s' -> 布尔值: %v\n", str5, bool1)
}
// 布尔值转字符串
bool2 := false
str6 := strconv.FormatBool(bool2)
fmt.Printf("布尔值 %v -> 字符串: '%s'\n", bool2, str6)
}#Base Conversion
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Println("=== 进制转换 ===")
num := 255
// 十进制转其他进制
binary := strconv.FormatInt(int64(num), 2) // 二进制
octal := strconv.FormatInt(int64(num), 8) // 八进制
hex := strconv.FormatInt(int64(num), 16) // 十六进制
fmt.Printf("十进制 %d:\n", num)
fmt.Printf(" 二进制: %s\n", binary)
fmt.Printf(" 八进制: %s\n", octal)
fmt.Printf(" 十六进制: %s\n", hex)
// 其他进制转十进制
fmt.Println("\n转换回十进制:")
if val1, err := strconv.ParseInt(binary, 2, 64); err == nil {
fmt.Printf("二进制 '%s' -> 十进制: %d\n", binary, val1)
}
if val2, err := strconv.ParseInt(octal, 8, 64); err == nil {
fmt.Printf("八进制 '%s' -> 十进制: %d\n", octal, val2)
}
if val3, err := strconv.ParseInt(hex, 16, 64); err == nil {
fmt.Printf("十六进制 '%s' -> 十进制: %d\n", hex, val3)
}
// 任意进制转换
fmt.Println("\n任意进制转换:")
base36 := strconv.FormatInt(int64(num), 36) // 36进制
fmt.Printf("十进制 %d -> 36进制: %s\n", num, base36)
if val4, err := strconv.ParseInt(base36, 36, 64); err == nil {
fmt.Printf("36进制 '%s' -> 十进制: %d\n", base36, val4)
}
}#🎯 Interface Type Conversion
#Type Assertions
package main
import "fmt"
func main() {
fmt.Println("=== 类型断言 ===")
// 创建接口变量
var i interface{} = "Hello, World!"
// 基本类型断言
if str, ok := i.(string); ok {
fmt.Printf("断言成功: %s (长度: %d)\n", str, len(str))
} else {
fmt.Println("断言失败: 不是字符串类型")
}
// 类型断言失败的情况
if num, ok := i.(int); ok {
fmt.Printf("是整数: %d\n", num)
} else {
fmt.Println("不是整数类型")
}
// 不安全的类型断言(可能panic)
defer func() {
if r := recover(); r != nil {
fmt.Printf("捕获panic: %v\n", r)
}
}()
// 这会触发panic,因为i不是int类型
// num := i.(int) // 取消注释会panic
fmt.Println("=== 多种类型处理 ===")
// 处理多种可能的类型
values := []interface{}{
42,
"Hello",
3.14,
true,
[]int{1, 2, 3},
}
for i, value := range values {
fmt.Printf("值 %d: ", i+1)
switch v := value.(type) {
case int:
fmt.Printf("整数: %d\n", v)
case string:
fmt.Printf("字符串: %s\n", v)
case float64:
fmt.Printf("浮点数: %.2f\n", v)
case bool:
fmt.Printf("布尔值: %v\n", v)
case []int:
fmt.Printf("整数切片: %v\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
}
}#Interface Conversion Examples
package main
import "fmt"
// 定义接口
type Shape interface {
Area() float64
}
type Drawable interface {
Draw()
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Draw() {
fmt.Printf("绘制半径为 %.2f 的圆形\n", c.Radius)
}
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Draw() {
fmt.Printf("绘制 %.2f x %.2f 的矩形\n", r.Width, r.Height)
}
func main() {
fmt.Println("=== 接口类型转换 ===")
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 4, Height: 3},
}
for i, shape := range shapes {
fmt.Printf("形状 %d:\n", i+1)
fmt.Printf(" 面积: %.2f\n", shape.Area())
// 类型断言检查是否实现了Drawable接口
if drawable, ok := shape.(Drawable); ok {
fmt.Print(" ")
drawable.Draw()
} else {
fmt.Println(" 不支持绘制")
}
// 使用类型断言获取具体类型
switch s := shape.(type) {
case Circle:
fmt.Printf(" 圆形半径: %.2f\n", s.Radius)
case Rectangle:
fmt.Printf(" 矩形尺寸: %.2f x %.2f\n", s.Width, s.Height)
}
fmt.Println()
}
}#🔄 Custom Type Conversion
#Defining Conversion Methods
package main
import (
"fmt"
"strconv"
"strings"
)
// 自定义类型
type Temperature float64
type Distance int
type Person struct {
Name string
Age int
}
// 温度转换方法
func (t Temperature) ToCelsius() Temperature {
return t
}
func (t Temperature) ToFahrenheit() Temperature {
return t*9/5 + 32
}
func (t Temperature) ToKelvin() Temperature {
return t + 273.15
}
func (t Temperature) String() string {
return fmt.Sprintf("%.2f°C", float64(t))
}
// 距离转换方法
func (d Distance) ToMeters() float64 {
return float64(d)
}
func (d Distance) ToKilometers() float64 {
return float64(d) / 1000
}
func (d Distance) ToMiles() float64 {
return float64(d) / 1609.34
}
func (d Distance) String() string {
return fmt.Sprintf("%d米", int(d))
}
// Person 转换方法
func (p Person) ToString() string {
return fmt.Sprintf("%s (%d岁)", p.Name, p.Age)
}
func (p Person) ToJSON() string {
return fmt.Sprintf(`{"name":"%s","age":%d}`, p.Name, p.Age)
}
func PersonFromString(s string) (Person, error) {
parts := strings.Split(s, ",")
if len(parts) != 2 {
return Person{}, fmt.Errorf("格式错误,应为: 姓名,年龄")
}
name := strings.TrimSpace(parts[0])
ageStr := strings.TrimSpace(parts[1])
age, err := strconv.Atoi(ageStr)
if err != nil {
return Person{}, fmt.Errorf("年龄格式错误: %v", err)
}
return Person{Name: name, Age: age}, nil
}
func main() {
fmt.Println("=== 自定义类型转换 ===")
// 温度转换
temp := Temperature(25)
fmt.Printf("温度转换:\n")
fmt.Printf(" 摄氏度: %s\n", temp.String())
fmt.Printf(" 华氏度: %.2f°F\n", temp.ToFahrenheit())
fmt.Printf(" 开尔文: %.2f K\n", temp.ToKelvin())
// 距离转换
distance := Distance(5000)
fmt.Printf("\n距离转换:\n")
fmt.Printf(" 米: %s\n", distance.String())
fmt.Printf(" 千米: %.2f公里\n", distance.ToKilometers())
fmt.Printf(" 英里: %.2f英里\n", distance.ToMiles())
// Person转换
person := Person{Name: "张三", Age: 25}
fmt.Printf("\nPerson转换:\n")
fmt.Printf(" 字符串: %s\n", person.ToString())
fmt.Printf(" JSON: %s\n", person.ToJSON())
// 从字符串创建Person
personStr := "李四, 30"
if p, err := PersonFromString(personStr); err == nil {
fmt.Printf(" 从字符串创建: %s\n", p.ToString())
} else {
fmt.Printf(" 创建失败: %v\n", err)
}
}#⚠️ Type Conversion Pitfalls
#Precision Loss and Overflow
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println("=== 类型转换陷阱 ===")
// 1. 浮点数精度损失
fmt.Println("1. 浮点数精度损失:")
var precise float64 = 1.23456789012345
var imprecise float32 = float32(precise)
var backToPrecise float64 = float64(imprecise)
fmt.Printf("原始 float64: %.15f\n", precise)
fmt.Printf("转为 float32: %.15f\n", imprecise)
fmt.Printf("转回 float64: %.15f\n", backToPrecise)
fmt.Printf("精度损失: %.15f\n", precise-backToPrecise)
// 2. 整数溢出
fmt.Println("\n2. 整数溢出:")
var big int64 = math.MaxInt32 + 1
var small int32 = int32(big) // 溢出
fmt.Printf("原始 int64: %d\n", big)
fmt.Printf("转为 int32: %d\n", small)
fmt.Printf("最大 int32: %d\n", math.MaxInt32)
// 3. 有符号无符号转换陷阱
fmt.Println("\n3. 有符号无符号转换:")
var negative int = -100
var positive uint = uint(negative) // 危险!
fmt.Printf("有符号 int: %d\n", negative)
fmt.Printf("转为 uint: %d\n", positive)
// 4. 字符串转换失败
fmt.Println("\n4. 字符串转换错误处理:")
invalidStrings := []string{"abc", "12.34.56", "", "999999999999999999999"}
for _, s := range invalidStrings {
if num, err := strconv.Atoi(s); err != nil {
fmt.Printf("字符串 '%s' 转换失败: %v\n", s, err)
} else {
fmt.Printf("字符串 '%s' 转换成功: %d\n", s, num)
}
}
// 5. 类型断言失败
fmt.Println("\n5. 类型断言安全检查:")
var unknown interface{} = 3.14
// 安全的类型断言
if str, ok := unknown.(string); ok {
fmt.Printf("是字符串: %s\n", str)
} else {
fmt.Println("不是字符串类型")
}
// 获取实际类型
fmt.Printf("实际类型: %T, 值: %v\n", unknown, unknown)
}#🛠️ Practical Conversion Utilities
#Generic Conversion Helper Functions
package main
import (
"fmt"
"reflect"
"strconv"
)
// 通用转换工具
type Converter struct{}
// 尝试将任意值转换为字符串
func (c Converter) ToString(value interface{}) string {
switch v := value.(type) {
case string:
return v
case int, int8, int16, int32, int64:
return fmt.Sprintf("%d", v)
case uint, uint8, uint16, uint32, uint64:
return fmt.Sprintf("%d", v)
case float32, float64:
return fmt.Sprintf("%g", v)
case bool:
return strconv.FormatBool(v)
case nil:
return ""
default:
return fmt.Sprintf("%v", v)
}
}
// 尝试将字符串转换为指定类型
func (c Converter) FromString(s string, targetType reflect.Type) (interface{}, error) {
switch targetType.Kind() {
case reflect.String:
return s, nil
case reflect.Int:
return strconv.Atoi(s)
case reflect.Int64:
return strconv.ParseInt(s, 10, 64)
case reflect.Float64:
return strconv.ParseFloat(s, 64)
case reflect.Bool:
return strconv.ParseBool(s)
default:
return nil, fmt.Errorf("不支持的类型: %v", targetType)
}
}
// 检查两个值是否可以进行类型转换
func (c Converter) CanConvert(from, to reflect.Type) bool {
return from.ConvertibleTo(to)
}
// 安全的类型转换
func (c Converter) SafeConvert(value interface{}, targetType reflect.Type) (interface{}, error) {
sourceType := reflect.TypeOf(value)
if sourceType == targetType {
return value, nil
}
if !sourceType.ConvertibleTo(targetType) {
return nil, fmt.Errorf("无法从 %v 转换到 %v", sourceType, targetType)
}
sourceValue := reflect.ValueOf(value)
convertedValue := sourceValue.Convert(targetType)
return convertedValue.Interface(), nil
}
func main() {
converter := Converter{}
fmt.Println("=== 通用转换工具测试 ===")
// 测试转换为字符串
values := []interface{}{
123,
3.14159,
true,
"hello",
nil,
[]int{1, 2, 3},
}
fmt.Println("转换为字符串:")
for _, value := range values {
str := converter.ToString(value)
fmt.Printf(" %T(%v) -> string(%s)\n", value, value, str)
}
// 测试从字符串转换
fmt.Println("\n从字符串转换:")
stringValues := map[string]reflect.Type{
"123": reflect.TypeOf(int(0)),
"3.14": reflect.TypeOf(float64(0)),
"true": reflect.TypeOf(bool(false)),
"hello": reflect.TypeOf(string("")),
}
for str, targetType := range stringValues {
if result, err := converter.FromString(str, targetType); err == nil {
fmt.Printf(" string(%s) -> %v(%v)\n", str, targetType, result)
} else {
fmt.Printf(" string(%s) -> %v 转换失败: %v\n", str, targetType, err)
}
}
// 测试安全转换
fmt.Println("\n安全类型转换:")
testCases := []struct {
value interface{}
target reflect.Type
}{
{int(42), reflect.TypeOf(float64(0))},
{float64(3.14), reflect.TypeOf(int(0))},
{true, reflect.TypeOf(int(0))},
{"hello", reflect.TypeOf(int(0))},
}
for _, tc := range testCases {
if result, err := converter.SafeConvert(tc.value, tc.target); err == nil {
fmt.Printf(" %T(%v) -> %v(%v)\n", tc.value, tc.value, tc.target, result)
} else {
fmt.Printf(" %T(%v) -> %v 转换失败: %v\n", tc.value, tc.value, tc.target, err)
}
}
}#🎓 Summary
In this chapter, we explored Go type conversion in depth:
- ✅ Explicit conversion: conversions between basic data types
- ✅ String conversion: using the strconv package and base conversion
- ✅ Interface conversion: type assertions and interface type checks
- ✅ Custom conversion: adding conversion methods to custom types
- ✅ Conversion pitfalls: precision loss, overflow, and other common issues
- ✅ Practical utilities: implementing generic conversion helper functions
Understanding and mastering type conversion is essential for writing robust Go code.
Next, we will learn about Go Interfaces, the core feature of object-oriented programming in Go.
::: tip Type Conversion Recommendations
- Always use explicit type conversion; Go does not support implicit conversion
- Watch for precision loss and overflow when converting numeric types
- Check the ok return value when using type assertions
- Handle errors that may occur during string conversion :::