本专栏文章持续更新 ,新增内容使用蓝色表示。
食用指南
本文适合有 C++ 基础的朋友,想要快速上手 Go 语言。可直接复制代码在 IDE 中查看,代码中包含详细注释和注意事项。
Go 的环境搭建请参考以下文章:
【Go】C++ 转 Go 第(一)天:环境搭建 Windows + VSCode 远程连接 Linux -CSDN博客
变量声明与使用
Go 语言对变量的要求非常严格,float32 和 float64 是不同的类型,且没有自动类型转换机制。

C++ vs Go 变量声明对比
特性 | C++ | Go |
---|---|---|
类型声明 | int a = 5; | var a int = 5 |
类型推导 | auto b = "hello"; (C++14+) | b := "hello" |
多变量声明 | int x=1, y=2; | x, y := 1, 2 |
默认值 | 未初始化是未定义行为 | 自动零值初始化 |
注意事项:
Go 中没有 char 类型,使用 byte(ASCII) 和 rune(Unicode)。
变量声明后必须使用,否则编译报错。
:=简短声明只能在函数内部使用。
var.go
Go
// 声明变量
package main
import (
"fmt"
)
// 二、全局变量声明
var e int
var f float64 = 9
var g = "q"
// var h:=1 // := 只能用在函数体内使用
func main() {
// 一、局部变量声明
// 默认值是0
var a int
fmt.Println("a =", a)
// go 中没有 char 字符类型,但是有byte (ASCII) / rune (Unicode)
// 带初始化值
var b int = 8
fmt.Println("b =", b)
// 自动匹配,相当于auto
// 1. var
var c = "var c"
// 使用类型推导可以使用 %v 占位符
fmt.Printf("c = %v \t", c) // 非格式化输出,带换行符
fmt.Printf("type : %T \n", c) // 格式化输出
// 2. :=
d := 5.5
fmt.Printf("d = %v \t", d)
fmt.Printf("type : %T \n", d)
fmt.Println("e =", e)
fmt.Println("f =", f)
fmt.Println("g =", g)
// fmt.Println("h =", h)
// 三、多个变量声明
// 1. 单行
// 1) 同一种数据类型
var a1, a2 int = 56, 78
fmt.Println("a1 =", a1, ",", "a2 =", a2)
// 2) 不同数据类型(自动匹配)
var b1, b2 = "hello", 8.9
fmt.Printf("b1 = %v \t", b1)
fmt.Printf("type : %T \n", b1)
fmt.Printf("b2 = %v \t", b2)
fmt.Printf("type : %T \n", b2)
// 2. 多行
var (
c1 int = 1
c2 bool = false
)
fmt.Println("c1 =", c1, ",", "c2 =", c2)
}
执行结果

常量与iota枚举
iota 是 Go 语言的常量计数器,只能在 const 内部使用。
iota 特性:
每遇到一个 const 关键字,iota 重置为0
const 声明块中每新增一行,iota 自增1
支持在表达式中使用 iota
const.go
Go
package main
import (
"fmt"
)
// 二、const 定义枚举类型
const (
apple = 0
banana = 1
)
// 可在 const 中添加关键字 iota(只能在const内部使用),第一行的 iota 的默认值是0,之后每行 iota 加1。
// 读法: i o ta
const (
_ = iota // 跳过 0
monday // 1
tuesday // 2
wednesday // 3
)
const (
cat = iota * 2 // 0 * 2
dog // 1 * 2
panda // 2 * 2
)
const (
a, b = iota + 1, iota + 2 // iota = 0, a = iota + 1 = 1, b = iota + 2 = 2
a1, b1 // iota = 1, a1 = iota + 1 = 2, b1 = iota + 2 = 3
a2, b2 // iota = 2, a2 = iota + 1 = 3, b2 = iota + 2 = 4
c, d = iota * 2, iota * 3 // iota = 3, c = iota * 2 = 6, d = iota * 3 = 9
c1, d1
c2, d2
)
func main() {
// 一、常量
const x string = "xian"
fmt.Println("x =", x)
// x = "xining" // 只读
fmt.Printf("apple=%d, banana=%d \n", apple, banana)
fmt.Printf("monday=%d, tuesday=%d, wednesday=%d\n", monday, tuesday, wednesday)
fmt.Printf("cat=%d, dog=%d, panda=%d\n\n", cat, dog, panda)
fmt.Printf("a=%d, b=%d \n", a, b)
fmt.Printf("a1=%d, b1=%d \n", a1, b1)
fmt.Printf("a2=%d, b2=%d \n\n", a2, b2)
fmt.Printf("c=%d, d=%d \n", c, d)
fmt.Printf("c1=%d, d1=%d \n", c1, d1)
fmt.Printf("c2=%d, d2=%d \n", c2, d2)
}
执行结果

函数
特性
-
参数顺序为参数名在前,类型在后。
-
Go 的返回值中没有 void,不需要返回值时直接省略返回类型。
-
Go 语言支持多返回值。
-
Go 中只有值传递,但可以传递指针来修改原值。
func.go
Go
package main
import "fmt"
// 形参的变量名和类型和C++的相反,末尾的是返回值类型。没有返回值,末尾可以不写
// 注意:go中没有void关键字,不需要返回值时直接省略
// go中只有值传递,但是传递的值不同,结果也不同
// 一、返回单个匿名返回值
func test(a int, b int) bool {
fmt.Println("-------test-------")
fmt.Println("a =", a, "b =", b)
c := true
return c
}
// 二、返回多个匿名返回值
func test1(a int, b string) (int, string) {
fmt.Println("-------test1------")
fmt.Println("a =", a, "b =", b)
return a, b
}
// 三、返回多个有名返回值
// 1. 多个返回值类型不同
func test2(a int, b string) (e float64, f string) {
fmt.Println("-------test2------")
fmt.Println("a =", a, "b =", b)
// 这两个变量也属于函数形参,在未赋值之前使用不会报错,前者默认为0,后者默认为空
// 防止不可控的野指针、野地址的出现
fmt.Println("e =", e, "f =", f)
// go没有隐式类型转换,比如将float64改为float32或者int都会报错
e = 17.3
f = "world"
return
}
// 2. 多个返回值类型相同
func test3(a int, b string) (e, f int) {
fmt.Println("-------test3------")
fmt.Println("a =", a, "b =", b)
return 6, 7
}
// 传递指针,函数内更改会影响原来的值
func change(n *int) {
*n = 99
}
func main() {
c := test(1, 2)
// 注意go中定义的变量必须要使用,否则会报错
fmt.Println("c =", c)
// 多返回值时, 可以使用下划线 _ 忽略不需要的返回值
_, d := test1(3, "hello")
fmt.Println("d =", d)
e, f := test2(4, "world")
fmt.Println("e =", e, "f =", f)
e1, f1 := test3(5, "word")
fmt.Println("e1 =", e1, "f1 =", f1)
fmt.Println("\n======传指针=======")
// 使用时传地址
num := 7
fmt.Println("未调用之前:", num)
change(&num)
fmt.Println("调用之后:", num)
}
执行结果

init 函数与包导入
目录结构如下所示:

导入方式说明
-
标准导入:通过包名调用导出函数
-
匿名导入:只执行包的init函数,不直接使用包中其他函数
-
别名导入:为长包名设置简短别名
-
导入点:将包中全部方法导入当前作用域(谨慎使用)
lib1/lib1.go
Go
package lib1
import "fmt"
func init() {
fmt.Println("-----lib1.init()-----")
}
// lib1包提供的API
// 以下函数名大写表示对外开放
// 小写则表示当前函数只能再包内调用
func Lib1Test() {
fmt.Println("-----lib1Test()-----")
}
lib2/lib2.go
Go
package lib2
import "fmt"
func init() {
fmt.Println("-----lib2.init()-----")
}
// lib2包提供的API
// 以下函数名大写表示对外开放
// 小写则表示当前函数只能再包内调用
func Lib2Test() {
fmt.Println("-----lib2Test()-----")
}
main.go
Go
package main
// 暂时采用这种写法
// 导包时会调用对应的 init 函数
import (
// 从 GOPATH 开始的相对路径
// 1. 标准导入
"GoLangStudy/5_initStudy/lib1"
"GoLangStudy/5_initStudy/lib2"
// 2. 匿名导入(_+空格)
// go 对语法要求严格,导包不使用,会报错
// 如果只执行包的 init() 函数,不直接使用包中的其他函数,可通过匿名导包实现
//_ "GoLangStudy/5_initStudy/lib2"
// 3. 别名导入
// 包名很长的时候可以使用
// mylib2 "GoLangStudy/5_initStudy/lib2"
// 4. 导入点(谨慎使用)
// 将包中的全部方法导到当前包的作用域中,可直接调用API
// 不同包可能会出现同名函数,不推荐生产上使用
// . "GoLangStudy/5_initStudy/lib2"
)
func main() {
// 1. 通过导包,可以调用 lib1 的函数。
lib1.Lib1Test()
lib2.Lib2Test()
// 3. 别名调用方式
// mylib2.Lib2Test()
// 4. 导入点
// Lib2Test()
}
执行结果

如有问题或建议,欢迎在评论区中留言~