Skip to content

1.2 语言基础概览

本章其余文章按主题拆开讲解语法与库用法。建议在读完 1.1 开发环境搭建指南 后阅读本文,串起 语言特点、类型地图、程序如何启动、运算符与 _、注释习惯;其中别处有专节的只点到为止,并给出链接。

Go 语言的主要特性

1. 起源与背景

21 世纪初,Google 内部在维护大规模 C++ 基础设施时,面临编译慢、依赖复杂、难以发挥多核等问题。Rob PikeKen ThompsonRobert Griesemer 等希望设计一门编译快、语法简单、适合网络与多核的语言。

  • 2009 年 11 月:以开源项目形式公开发布,官网与文档见 https://go.dev/
  • 2012 年 3 月:正式发布 Go 1,并作出 Go 1 兼容性承诺——在 1.x 系列内,尽量保证源码级兼容,便于长期维护。

语言由 Google 发起,现由 Go 团队与全球社区共同演进,常见别称 Golang(来自早期域名 golang.org)。

2. 设计理念

  • 简单可读:控制结构与关键字数量克制,强调显式、直白的代码,减少「炫技」写法;用组合小接口组织程序,而不是深层类继承。
  • 工程优先:内置 go fmt 统一风格、go test 测试、模块(modules) 管理依赖版本,把团队协作与交付成本考虑进语言生态。
  • 并发是语法的一部分goroutine(轻量协程)与 channel(通道)进入语言核心,配合 select,把并发模型说清楚、写清楚。
  • 安全与效率的折中静态类型在编译期发现大量错误;垃圾回收(GC)减轻手工内存管理;在需要与 C 互操作或极致性能时,可使用 cgounsafe(均需审慎)。

一句话:让程序员用有限、一致的手段,稳定地写出可维护的服务端与系统软件。

3. 词法基础:关键字、声明与可见性

项目说明
源文件扩展名为 .go;可执行程序入口包名为 main,且需包含 func main()
关键字(25 个)不能用作自定义标识符;完整列表见下。
预声明标识符语言还预置了 intstringtruenilappendmakelen 等名称,含义见 语言规范
四种声明顶层常用声明:var(变量)、const(常量)、type(类型别名或新类型)、func(函数或方法)。
可见性(导出规则)标识符(类型、函数、字段、方法等)若首字母大写,则对其它包可见(可导出);首字母小写仅本包内可见。这是 Go 访问控制的核心约定,无 public/private 关键字。

25 个关键字如下(顺序可按需查阅 语言规范):

text
break    default     func    interface   select
case     defer       go      map         struct
chan     else        goto    package     switch
const    fallthrough if      range       type
continue for         import  return      var

包、文件与 import 的组织方式,在后续章节结合示例说明。

4. 语言机制与工具链

在掌握关键字与可见性之后,下面这些能力贯穿日常开发,本章后文与其它章节会分主题展开。

类别要点
类型与内置值静态类型 + := 等推断;内置 slicemapchan 等,直接支持容器与并发编程。
函数与错误多返回值;常用 (结果, error) 显式处理错误;panic/recover 用于少数真正「异常」场景。
接口与组合interface 描述行为,类型隐式实现接口,无需 implements
并发goroutinechannelselect;标准库另有 synccontext 等。
反射与互操作reflect 运行时检视类型(框架、序列化常用);cgo 调用 C 代码(构建与跨平台成本更高)。
编译与部署静态编译,常得到单个可执行文件;设置 GOOS / GOARCH交叉编译
依赖与工具Go modulesgo.mod / go.sum);go fmtgo testgo vetgo doc 等命令行工具。

类型体系一览

Go 的类型可先粗分为 基本数据类型复合数据类型。下面按「本章相关小节」做索引,详细定义与示例请看对应文章

基本数据类型

语言内置的标量层面类型,赋值/传参时通常拷贝「整份位模式」string 由运行时优化为共享底层,表现上仍像值)。

子类内容提要本章延伸阅读
布尔true / false1.8 布尔类型
数值有符号/无符号整型、float32/float64complex64/complex1281.4 整型与浮点型
字符与文本byteuint8)、runeint32)、string(不可变文本)1.5 byte、rune 与字符串

复合数据类型

由其它类型组合或抽象而来;定长数组、结构体等往往整份拷贝;切片、映射、通道变量里多是头/描述符,拷贝头后底层数据常共享

子类内容提要本章延伸阅读
数组与切片[n]T[]T1.6 数组与切片
映射map[K]V1.7 字典
指针*T(拷贝的是地址)1.9 指针
通道chan T(并发与同步)后续并发章节
函数func,一等公民第二章函数相关
接口interface{...},隐式实现第二章接口相关

值类型与引用类型(简)

入门时常把类型分成两类:

  • 值类型:变量里直接放数据本身,赋值、传参时一般拷贝一整份内容。例如 intbool、浮点、定长数组 [n]T、结构体 struct。若结构体很大,可以传 *T,只拷指针(一个地址),避免大块复制。
  • 引用类型(常见说法):变量里主要放地址,或通过地址找到的数据,一处修改可能让别处也看到变化。例如 指针 *T切片、映射、通道的变量里带有长度、指针、容量等头信息,赋值、传参虽然拷的是「头」这份内容,但底层数据仍可能被多处共用

Go 的函数默认按值传参:对小类型传的是整份数据,对 slice、map 等传的是头信息(其中含指针)。make / new 与切片、映射的配合见 2.10 make 和 new 的区别;变量与类型还可对照 1.3 变量声明

main 函数与 init 函数

可执行程序使用 package main,下面分别说明入口函数 main 与包初始化函数 init

可执行程序入口

  • 生成命令行可执行文件的包,包名一般为 package main,其中必须有一个 func main(),作为进程入口。
  • main 函数无参数、无返回值(进程退出码通过 os.Exit 等方式表达,不宜滥用)。
go
package main

import "fmt"

func main() {
	fmt.Println("hello")
}

init 函数(包初始化)

签名只能是 func init()无参、无返回值),由运行时在调用 main 之前自动执行,不能在业务代码里手动调用 init()。每个包、每个 .go 文件都可以写多个 init

启动顺序依赖包先完成(包级变量 → 各 init)→ 本包包级变量 → 本包init → 最后 main(仅 package main)。同一包内多个 init 的顺序由文件名字典序、文件内书写顺序等规则决定,业务代码中不要依赖过于精细的顺序假设。

适合:注册、包内默认状态等;避免重逻辑、阻塞、难测的副作用。

go
package main

import "fmt"

func init() { fmt.Println("init:先于 main") }

func main() { fmt.Println("main:进程入口") }

运算符概览

常用运算符分类如下(细规则见语言规范与各节例题)。

类别运算符备注
算术+ - * / %整数除法向零取整;% 仅整数
比较== != < <= > >=返回布尔值
逻辑与、或、非可能短路求值
位运算与、或、异或、清、移位&&^^<<>>
赋值= += -= *= /=左值须可寻址
指针与通道& * <-取址、解引用、通道发送/接收
其他. () []选择、调用、下标/切片

Go 没有三元运算符 ?:,也没有自增/自减表达式返回值(i++ 是语句,不是表达式)。

下划线 _

含义与规则

_空白标识符:语法上必须写出标识符或接收值时,用 _ 表示丢弃该值、不引入可引用的新名字。同一作用域内可多次使用 _,不会像普通变量那样因「重复声明」报错。

多返回值、map 与通道

必须接住某一侧但不用时,写在 _ 上。

  • mapv, _ := m[k];若只关心键是否存在,常用 _, ok := m[k]
  • 多返回值:例如 n, err := io.Read(...) 只关心 err 时写作 _, err := io.Read(...)
  • 通道v, _ := <-ch;需要区分零值与通道关闭时,用 v, ok := <-ch

for range:忽略下标或元素

  • 只要元素、不要下标:for _, v := range s { ... }
  • 只要下标、不要元素:惯用 for i := range s { ... },一般不必写 for i, _ := range

空白导入(仅执行 init

不需要在代码里写包名,但需要该包的 init 副作用(例如向 database/sql、图像解码器等注册驱动)时,使用空白导入:

go
import _ "image/png" // 执行包内 init,注册 PNG 解码器

包被正常导入时也会执行 init;前缀 _ 表示刻意不引用该包导出符号,从而避免「导入了未使用」的编译错误。

编译期接口实现检查

若希望某类型必须实现某接口,可在包级写(惯用法):

go
var _ io.Writer = (*MyWriter)(nil)

*MyWriter 未满足 io.Writer,会在编译期失败,便于防止接口与实现脱节。

:=、作用域等更细的规则见 1.3 变量声明 中的 匿名变量 小节。

代码注释

行注释与块注释

  • //:行注释,从 // 到行尾。最常用。
  • /**/:块注释,可跨行;多用于大段说明或临时屏蔽代码(不宜嵌套)。
go
// 单行说明

/*
  多行说明
  或暂时注释掉一段代码
*/

包注释与导出符号的文档注释

  • 紧挨在 package 行之前的块注释,且中间无空行,通常作为包说明go doc 会展示)。
  • 导出名字(首字母大写)若在其声明前写以该名字开头的句子,会被 go doc 当作文档串起来;推荐用完整句子。
go
// Package mypkg 演示包注释习惯。
package mypkg

// User 表示一个用户;字段导出规则见后续结构体章节。
type User struct {
	Name string
}

工具链习惯:注释由完整句子构成,导出标识符的注释以它的名字起句,便于生成文档与 IDE 提示。

建议阅读顺序

  1. 1.1 开发环境搭建指南 — 装好工具链。
  2. 1.2 本文(语言基础概览) — 建立整体印象(你正在阅读)。
  3. 1.3 变量声明var:=、包级与函数内。
  4. 按上表从 1.4 起补全类型与流程控制各篇;并发、接口、错误处理等在后续章节继续深入。

这样读完本章,能对「Go 是什么风格、类型如何划分、程序如何启动、运算符与注释怎么用」形成整体认识,便于继续阅读本章后续各节。