
Go 允许在初始化指针切片时省略每个元素前的 & 和类型名,只要切片元素类型(如 *T)与字面量结构体类型(T)严格匹配,编译器会自动补全取地址操作。
go 允许在初始化指针切片时省略每个元素前的 `&` 和类型名,只要切片元素类型(如 `*t`)与字面量结构体类型(`t`)严格匹配,编译器会自动补全取地址操作。
在 Go 中,以下代码能成功编译并运行:
package main
import "fmt"
type index struct {
i, j int
}
func main() {
indices := []*index{{0, 1}, {1, 3}} // ✅ 合法:自动推导为 &index{0,1}, &index{1,3}
fmt.Println(*indices[1]) // 输出:{1 3}
}这并非语法糖或特殊例外,而是 Go 语言规范中明确定义的 复合字面量类型省略规则(Composite Literal Type Elision)。根据 Go 语言规范:
在数组、切片或映射类型的复合字面量中,若其元素(或键)本身也是复合字面量,则当该元素类型与容器的元素(或键)类型完全一致时,可省略字面量的类型;同理,若元素是复合字面量的地址,且容器元素类型为
*T,则可省略&T,仅保留{...}。
换句话说:
-
[]*index声明了“这是一个存放*index的切片”; - 编译器据此推断:
{0, 1}必须被解释为index{0, 1}的地址,即&index{0, 1}; - 因此
{0, 1}是&index{0, 1}的合法简写形式。
⚠️ 注意事项:
- 此简写*仅适用于切片/数组/映射的元素类型精确匹配 `T
且字面量为T{...}` 的场景**; - 若目标类型是接口(如
[]interface{}),则无法自动取址,必须显式写出&index{0,1}; - 若结构体字段未按定义顺序提供,或含嵌套结构,仍需完整指定字段名(如
&index{i: 0, j: 1}),此时简写不适用; - 简写不改变语义:每个
{...}仍会创建一个匿名的index实例,并对其取地址——内存行为与&index{...}完全等价。
✅ 正确使用示例:
// ✅ 类型匹配 → 自动取址
ptrs := []*strings.Builder{{}, {}} // 等价于 []*strings.Builder{&strings.Builder{}, &strings.Builder{}}
// ❌ 类型不匹配 → 必须显式取址
var anys []interface{} = []interface{}{&index{0, 1}, &index{1, 3}} // 不能写作 { {0,1}, {1,3} }总结:这一特性提升了代码简洁性与可读性,但其本质是编译器基于类型上下文的确定性推导,而非隐式转换。理解它有助于编写更地道的 Go 代码,也避免在泛型或接口场景下误用导致编译错误。

















