首页 / Go 语言入门教程 / 类型转换与推断

Go 语言入门教程

类型转换与推断

本教程共 80 篇 · 第 14 篇 · 更新于 2026-07-27 · 约 7 分钟阅读

GoGo 入门教程类型转换类型推断newGo 1.26类型系统

14. 类型转换与推断

本节目标:掌握 Go 的显式类型转换语法,理解类型推断的工作方式,了解 Go 1.26 新增的 new(expr) 用法。

Go 没有隐式转换

很多语言会自动做类型转换。比如 C 语言里 intfloat 会自动把 int 转成 float。Go 不行,Go 要求所有类型转换都必须显式写出来

var a int = 10
var b float64 = 3.14
// c := a + b  // 报错:mismatched types int and float64
c := float64(a) + b  // 正确,先把 a 转成 float64

这个设计的好处是:你永远不会因为隐式转换而遇到意料之外的行为。代码里每一处类型转换都明明白白。

Note

Go 里 intint32 是不同的类型,即使 int 在 32 位平台上就是 32 位,也不能直接赋值,必须显式转换。

类型转换语法

格式:类型名(值)

数值类型之间

var i int = 42
var f float64 = float64(i)  // int -> float64
var j int = int(f)          // float64 -> int(截断小数部分)

fmt.Println(f)  // 42
fmt.Println(j)  // 42

var f2 float64 = 3.99
var i2 int = int(f2)
fmt.Println(i2)  // 3,小数部分直接丢弃,不是四舍五入

整数和字符串之间

// 整数转字符串(按 Unicode 码点)
s := string(65)
fmt.Println(s)  // A

字符串转整数需要用 strconv 包,记得在文件顶部导入:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 字符串转整数
    n, err := strconv.Atoi("42")
    fmt.Println(n, err)  // 42 <nil>

    // 整数转字符串(数字本身)
    numStr := strconv.Itoa(42)
    fmt.Println(numStr)  // 42
}
Warning

string(65) 得到的是 "A"(码点 65 对应的字符),不是 "65"。要把数字 42 转成字符串 "42",用 strconv.Itoa(42)

字符串和字节切片

s := "Hello"
b := []byte(s)    // string -> []byte
s2 := string(b)   // []byte -> string

r := []rune(s)    // string -> []rune
s3 := string(r)   // []rune -> string

不同整数类型之间

var i32 int32 = 100
var i64 int64 = int64(i32)  // int32 -> int64
var i int = int(i32)        // int32 -> int
var u uint = uint(i64)      // int64 -> uint
Tip

大类型转小类型时要注意截断。比如 int64int8,如果值超过 127,结果不可预期。

类型推断

Go 有类型推断,你在用 :=var x = value 时不需要写类型,编译器会自动推断。

基本推断

i := 42        // int
f := 3.14      // float64
s := "hello"   // string
b := true      // bool
r := 'A'       // rune (int32)

从函数返回值推断

func getName() string {
    return "Go"
}

name := getName()  // 推断为 string

多变量推断

x, y := 10, 20       // 都是 int
a, b := 1, 3.14      // a 是 int,b 是 float64

字面量的类型推断

整数字面量默认是 int,如果赋值给特定类型的变量,会自动适配:

var i8 int8 = 42    // 42 适配为 int8
var f32 float32 = 3.14  // 3.14 适配为 float32

但如果字面量超出目标类型范围,编译器会报错:

var i8 int8 = 200  // 报错:constant 200 overflows int8

new 函数

new 是 Go 的内置函数,用来分配内存并返回指向零值的指针。

基本用法

p := new(int)    // 分配一个 int,返回 *int
fmt.Println(*p)  // 0(零值)
*p = 42
fmt.Println(*p)  // 42

new(T) 返回 *T,指向一个类型为 T 的零值变量。

new 和直接声明的区别

// 方式一:直接声明
var x int = 42

// 方式二:new
p := new(int)
*p = 42

大部分时候你不需要 new,直接用 var:= 就行。new 主要用在需要指针的场景,比如结构体指针。

Go 1.26 新增:new(expr)

Go 1.26 给 new 增加了一个新能力:可以直接传入一个表达式作为初始值。

// Go 1.26 之前
age := 18
p := &age  // 先声明变量再取地址

// Go 1.26 新写法
p := new(18)  // 直接创建一个值为 18 的 *int

这在处理可选字段时特别有用。比如 JSON 里的可选字段用指针表示:

type Person struct {
    Name string `json:"name"`
    Age  *int   `json:"age"` // nil 表示不输出
}

// Go 1.26 之前,要设置 age 字段得先声明变量
yearsOld := 25
p := Person{Name: "Go", Age: &yearsOld}

// Go 1.26,一行搞定
p := Person{Name: "Go", Age: new(25)}

也可以传表达式:

func yearsSince(t time.Time) int {
    return int(time.Since(t).Hours() / (365.25 * 24))
}

p := Person{
    Name: "Go",
    Age:  new(yearsSince(birthday)),
}
Note

new(expr) 是 Go 1.26 引入的新特性。它让可选指针字段的赋值变得简洁了很多。如果你的 go.modgo 版本低于 1.26,用不了这个语法。

赋值与类型安全

Go 的类型系统在赋值时会严格检查:

var a int = 10
var b int64

// b = a  // 报错:cannot use a as int64
b = int64(a)  // 正确

即使是 intint64,在 64 位平台上大小完全一样,也不能直接赋值。这是 Go 的设计选择:宁可多写类型转换,也不要隐式转换带来的模糊。

类型别名和转换

byteuint8 的别名,runeint32 的别名。别名类型之间不需要转换:

var b byte = 65
var u uint8 = b  // 直接赋值,不需要转换,因为 byte 就是 uint8

var r rune = 65
var i int32 = r  // 直接赋值,因为 rune 就是 int32

intint32 不是别名关系(即使在 32 位平台上大小一样),需要显式转换。

常见的转换函数

除了类型转换语法,strconv 包提供了更多转换工具:

import "strconv"

// 字符串转整数
n, err := strconv.Atoi("42")

// 整数转字符串
s := strconv.Itoa(42)

// 字符串转 float
f, err := strconv.ParseFloat("3.14", 64)

// float 转字符串
fs := strconv.FormatFloat(3.14, 'f', 2, 64)  // "3.14"

// 字符串转 bool
b, err := strconv.ParseBool("true")

学完这节你能做什么

  • 理解 Go 为什么没有隐式转换
  • 类型名(值) 语法做显式转换
  • 知道 string(65)strconv.Itoa(65) 的区别
  • 用类型推断简化变量声明
  • 用 Go 1.26 的 new(expr) 简化可选指针赋值

下一节讲自定义类型和类型别名。