零基础学Go:用一顿饭的时间掌握核心语法
传说Go的语法简洁到"你看着代码就能猜出它的意思"。今天,我们就用最少的术语,最快的方式,把Go的基础语法走一遍。
阅读时间 :约15分钟(含动手敲代码)
读者对象:有一点编程基础(知道变量、循环、函数是什么),但没写过Go的同学
一、开篇:一个完整的Go程序长什么样?
让我们从经典的"Hello World"开始:
go
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
看到什么特点了?
- 没有分号结尾(编译器会自动加,你不需要操心)
main函数没有返回值- 左大括号
{必须和函数名在同一行(否则编译错误------Go有强制代码风格)
运行它:go run main.go
如果你来自C/C++/Java,最大的不同是:类型后置 、包强制管理 、简洁到没有while关键字。
二、变量声明:Go让你"反过来写"
标准写法(显式类型)
go
var name string = "张三"
var age int = 18
类型推断(让编译器猜)(常用)
go
var name = "张三" // 自动推断为string
var age = 18 // 自动推断为int
短变量声明(最常用,只能在函数内用)
go
name := "张三" // 等价于 var name = "张三"
age := 18
这是Go程序员写代码的主流方式 。冒号等号
:=代表"声明并赋值"。
多变量声明
go
var x, y int = 1, 2
a, b := "hello", true
常量(不可修改)
go
const Pi = 3.14159
const (
StatusOK = 200
NotFound = 404
)
三、基本数据类型(够用就行)
| 类型 | 说明 | 例子 |
|---|---|---|
bool |
布尔 | true / false |
string |
字符串 | "hello" |
int, int8, int64 |
整数 | 42 |
float32, float64 |
浮点数 | 3.14 |
byte |
字节(等同于uint8) | 'A' |
rune |
Unicode码点(等同于int32) | '中' |
go
var isOK bool = true
var score float64 = 95.5
var ch byte = 'A'
四、控制结构:少即是多
条件判断 if(不需要括号)
go
age := 20
if age >= 18 {
fmt.Println("成年了")
} else {
fmt.Println("未成年")
}
神奇写法 :if 前面可以加一个简单语句
go
if age := 20; age >= 18 {
fmt.Println("成年了")
}
// age 在这里就失效了(作用域只在if块内)
循环:只有 for(没有while和do-while)
Go的设计哲学:一种写法就够了。
go
// 类似C的for
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// 充当while
sum := 1
for sum < 100 {
sum += sum
}
// 无限循环
for {
fmt.Println("跑不停")
break
}
switch(默认不穿透)
go
day := "Tuesday"
switch day {
case "Monday":
fmt.Println("周一")
case "Tuesday":
fmt.Println("周二")
default:
fmt.Println("其他")
}
注意:每个case后面不需要 写
break,执行完会自动跳出。想穿透用fallthrough。
五、函数:可以返回多个值
基本函数
go
func add(x int, y int) int {
return x + y
}
参数类型相同时可以简写:func add(x, y int) int
多返回值(Go的特色)
go
func divide(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为0")
}
return a / b, nil
}
// 调用
result, err := divide(10, 2)
if err != nil {
fmt.Println("出错:", err)
} else {
fmt.Println("结果:", result)
}
这种
(结果, 错误)的模式在Go标准库中随处可见。
命名返回值
go
func getCoordinates() (x, y int) {
x = 10
y = 20
return // 裸返回,返回x和y
}
六、数组 vs 切片(重点难点)
数组:固定长度,不太常用
go
var arr [3]int = [3]int{1, 2, 3}
arr[0] = 100
fmt.Println(len(arr)) // 3
切片:动态数组,天天用
go
// 创建切片
s := []int{1, 2, 3}
s = append(s, 4) // 追加元素
fmt.Println(s) // [1 2 3 4]
// 用make创建
s2 := make([]int, 5) // 长度5,容量5
s3 := make([]int, 3, 5) // 长度3,容量5
切片的切片:
go
numbers := []int{0,1,2,3,4,5}
sub := numbers[1:4] // [1,2,3] 从索引1到4(不含4)
数组用的少,切片才是真正的王者。记住:
append、len、cap是切片的三大常用操作。
七、map:字典/哈希表
go
// 声明并初始化
scores := map[string]int{
"张三": 95,
"李四": 87,
}
// 添加或修改
scores["王五"] = 92
// 读取
fmt.Println(scores["张三"]) // 95
// 判断key是否存在
value, ok := scores["赵六"]
if ok {
fmt.Println("找到:", value)
} else {
fmt.Println("不存在")
}
// 删除
delete(scores, "李四")
八、指针:有,但没那么可怕
Go有指针,但不支持指针算术 (不能 p++),安全很多。
go
x := 42
p := &x // p是指向x的指针
fmt.Println(*p) // 42(解引用)
*p = 100
fmt.Println(x) // 100
主要用于:
- 让函数修改外部变量
- 避免大结构体拷贝
九、结构体:Go的"类"(但没有继承)
go
type Person struct {
Name string
Age int
}
// 创建实例
p1 := Person{"张三", 18}
p2 := Person{Name: "李四", Age: 20}
// 访问字段
fmt.Println(p1.Name)
// 为结构体添加方法(注意:这里是函数外面写的)
func (p Person) SayHello() {
fmt.Printf("我是%s,今年%d岁\n", p.Name, p.Age)
}
// 指针接收者(可修改)
func (p *Person) SetAge(newAge int) {
p.Age = newAge
}
调用方法:
go
p1.SayHello()
p1.SetAge(19)
十、一个综合小例子:学生成绩管理系统(片段)
go
package main
import "fmt"
type Student struct {
Name string
Scores []int
}
func (s Student) Average() float64 {
total := 0
for _, score := range s.Scores {
total += score
}
return float64(total) / float64(len(s.Scores))
}
func main() {
stu := Student{
Name: "小明",
Scores: []int{88, 92, 79, 100},
}
fmt.Printf("%s的平均分是: %.2f\n", stu.Name, stu.Average())
}
运行输出:小明的平均分是: 89.75
写在最后:Go语法的"哲学"
你可能会觉得奇怪:
- 为什么只有
for,没有while? - 为什么
if不用括号? - 为什么类型写在变量名后面?
因为Go的设计者坚信:少就是多,显式优于隐式,规约大于配置。
学了上面这些(变量、循环、分支、函数、切片、map、结构体),你已经能用Go写绝大多数程序了。剩下20%的进阶内容(接口、并发、包管理、错误处理)可以边做项目边学。
下一步建议:用Go写一个命令行计算器,或者一个简单的HTTP服务。代码量不到50行,你会爱上这种感觉。
现在,打开终端,输入 go run 试试吧! 🚀