跳到主要内容

Literal(字面量)

字面量(literal)是在源码中直接写出的值或值的构造形式。Go 提供数值、rune、字符串等基本字面量,也提供数组、切片、映射、结构体和函数的字面量。理解字面量的类型推断与表示范围,可以避免溢出、乱码和初始化歧义。

整数字面量

整数可以使用十进制、二进制、八进制或十六进制表示:

package main

import "fmt"

func main() {
decimal := 42
binary := 0b101010
octal := 0o52
hexadecimal := 0x2A
readable := 1_000_000

fmt.Println(decimal, binary, octal, hexadecimal, readable)
}

这些写法的数值分别是 424242421000000。下划线可以提高长数字的可读性,不会改变数值,但必须出现在语法允许的数字分隔位置。

没有显式类型约束的整数常量可以保持任意精度,直到它被赋给变量、作为参数传入或参与需要具体类型的运算。目标类型必须能表示该常量:

const maxByte = 255

var valid uint8 = maxByte
// var overflow uint8 = 256 // 编译错误:uint8 无法表示 256

浮点数与复数字面量

浮点数字面量可以使用小数点或指数形式:

package main

import "fmt"

func main() {
price := 19.95
distance := 1.2e3
hexFloat := 0x1.8p1 // 1.5 × 2¹,即 3

fmt.Println(price, distance, hexFloat)
}

二进制指数形式中的 p 表示以 2 为底的指数。浮点数采用有限精度表示,像 0.1 这样的十进制小数通常不能被二进制浮点数精确表示;金额等需要精确十进制定点语义的数据不应直接依赖普通浮点运算。

虚数字面量以 i 结尾,可用于构造复数:

value := 2 + 3i

这里 value 的实部是 2,虚部是 3

Rune 字面量

rune 字面量使用单引号,表示一个 Unicode 码点,其默认类型为 rune,而 runeint32 的别名:

package main

import "fmt"

func main() {
letter := 'G'
chinese := '语'
newline := '\n'
unicode := '\u8BED'

fmt.Printf("%c %c %q %c\n", letter, chinese, newline, unicode)
}

单引号中必须表示一个码点或合法转义,不能写多个字符。rune 适合表达码点,不等同于用户感知的完整字符;某些视觉字符可能由多个码点组合而成。

字符串字面量

Go 有解释字符串和原始字符串两种写法。

解释字符串

双引号字符串会处理转义序列:

message := "line 1\nline 2\t\"Go\""
path := "C:\\temp\\app.log"

常见转义包括 \n\t\\\",以及 Unicode 转义 \uXXXX\UXXXXXXXX

原始字符串

反引号字符串不会解释反斜杠转义,可以跨越多行:

query := `SELECT id, name
FROM users
WHERE active = true`

windowsPath := `C:\temp\app.log`

原始字符串中不能直接包含反引号。它适合正则表达式、SQL 和多行模板,但换行和缩进会成为字符串内容的一部分。

Go 字符串本质上是只读字节序列,源码中的字符串通常使用 UTF-8。len 返回字节数,不是 rune 数量:

fmt.Println(len("Go语言")) // 8

truefalsenil

严格来说,truefalse 是预声明的布尔常量,nil 是预声明标识符,它们都不是关键字式字面量。日常代码仍直接使用它们:

enabled := true
var pointer *int = nil

nil 只能用于指针、函数、切片、映射、通道和接口等具有 nil 零值的类型,不能赋给整数、布尔值、字符串、数组或结构体。

复合字面量

复合字面量(composite literal)可以直接构造数组、切片、映射和结构体:

package main

import "fmt"

type User struct {
ID int
Name string
}

func main() {
array := [3]int{1, 2, 3}
slice := []string{"Go", "TypeScript"}
scores := map[string]int{"Go": 100, "TypeScript": 90}
user := User{ID: 1, Name: "Terry"}
userPointer := &User{ID: 2, Name: "Lan"}

fmt.Println(array, slice, scores, user, userPointer.Name)
}

结构体字面量在包外使用时,通常应写字段名。命名字段能抵抗字段顺序变化,也让初始化意图更清楚。映射和切片字面量会创建已初始化的值,而只声明未初始化变量得到的是 nil 映射或 nil 切片,两者后续操作能力不同。

数组长度还可以由元素数量推断:

levels := [...]string{"debug", "info", "error"}

函数字面量

函数字面量用于创建匿名函数,也可以捕获外层作用域中的变量:

package main

import "fmt"

func main() {
prefix := "Hello"
format := func(name string) string {
return prefix + ", " + name
}

fmt.Println(format("Go"))
}

捕获的是外层变量本身,而不是声明函数时的一份固定文本副本。闭包逃逸、循环变量和并发访问会带来更进一步的生命周期与同步问题,应结合函数和并发专题理解。

与 TypeScript 的区别

两种语言都支持十六进制、模板式多行文本、对象或集合初始化和匿名函数,但语义并不相同。Go 的单引号表示 rune,不是字符串;反引号原始字符串不执行 ${...} 插值;结构体和数组具有明确静态类型;未加类型的数值常量还具有 Go 特有的延迟定型与可表示性规则。

字符串的 UTF-8、码点和字节边界见 String(字符串);类型推断与可赋值性见 Type(类型)

小结

  • 整数支持多种进制和下划线分隔,无类型数值常量在进入具体类型时必须可表示。
  • 浮点数可能存在二进制表示误差,精确金额计算需要选择合适的数据表示。
  • rune 字面量表示一个 Unicode 码点,字符串则是只读字节序列。
  • 双引号字符串处理转义,反引号原始字符串保留大部分原始文本。
  • 复合字面量可以构造数组、切片、映射和结构体,函数字面量可以形成闭包。
  • truefalsenil 是预声明标识符,不是关键字。