Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
fmt.Println("Hello World!")
}

注释

  • 行注释://
  • 块注释:/**/
  • 文档注释:位于 package 之前的注释,以及在变量、函数之前的以变量名、函数名开头的注释

godoc 工具可根据文档注释,自动生成文档

变量

使用 var 关键字声明一个变量,类型后置

1
2
3
4
5
var a int = 10

// 先声明后初始化
var a int
a = 10

若变量在声明时未显式初始化,go 会自动赋零值

类型 零值
数值类型 0 或 0.0
布尔类型 false
字符串类型 “”
引用/复合类型 nil

当变量名为 _ 时,该变量在初始化后会被丢弃

go 支持类型推断

1
2
3
4
var a = 10  // a为int类型

// 使用:=运算符
b := 10 // 等价于var b = 10

定义多个变量

1
2
3
4
5
var (
a int = 10 // var a int = 10
b int // var b int
c = 20 // var c = 20
)

go 支持并行赋值,通常用于接收函数的多返回值

1
var a, b = 10, 20

类型转换

go 不支持隐式类型转换,所有的类型转换都必须是显式的,且必须能够转换成功,否则会引发编译时错误

1
2
a := 10.0
b := int(a) // b = 10

类型定义

使用 type 关键字可以定义一个类型,一般用于定义结构体或定义一个底层为基本类型的新类型

1
2
3
type MyInt int  // 定义了类型MyInt,它的底层为int,可以与int进行类型转换

var a MyInt = 10 // 可作为一般类型使用

定义多个类型

1
2
3
4
type (
MyInt int
MyString string
)

常量

使用 const 关键字定义一个常量,go 中只支持布尔类型、数值类型和字符串的常量,且必须在编译时确定常量值

1
2
const a int = 10
const s = "Hello World" // 支持类型推断

在 go 中,const 定义多个常量可以实现枚举的效果

1
2
3
4
5
const (
a = 0
b = 1
c = 2
)

若某行没有赋值,则沿用上一行的表达式进行赋值

1
2
3
4
5
const (
a = 0
b // 沿用表达式0,b = 0
c = 1
)

go 提供了一个常量计数器 iota,可以很方便的实现枚举定义,它在每个 const 块中的初始值为 0,每次调用时值加 1,结合沿用上一行赋值,枚举定义可实现如下

1
2
3
4
5
const (
a = iota // 0
b // 1
c // 2
)

iota 和沿用上一行赋值可以组成更加复杂的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const (
a = iota // 0
b // 1
_ // 2,初始化后被丢弃

// 并行赋值
// c = 3 + 1 = 4
// d = 3 + 2 = 5
c, d = iota + 1, iota + 2

// 沿用上一行赋值
// e = iota + 1 = 4 + 1 = 5
// f = iota + 2 = 4 + 2 = 6
e, f
)

函数

使用 func 关键字定义一个函数,函数的基本形式如下

1
2
3
func fun(param1 type1, param2 type2) (ret1 type1, ret2 type2) {
// ...
}

由于 go 编译器会自动添加分号,因此左大括号 { 必须位于行尾

返回值

go 支持多返回值,有以下形式

1
2
3
func fun1() {}  // 无返回值,省略括号
func fun2() int {} // 一个返回值,省略括号
func fun3() (int, int) {} // 多个返回值

go 支持命名返回值,即自动初始化返回值的命名变量,无需在函数体中声明

1
2
3
4
func fun(a int, b int) (c int) {
c = a + b // 可直接给变量c赋值,无需声明
return c
}

有以下形式

1
2
func fun1() (a int) {}  // 一个命名返回值
func fun2() (a int, b int) {} // 多个命名返回值

包与可访问性

每个 go 文件都只属于一个包,在 go 文件的第一条语句使用 package 关键字声明当前 go 文件属于哪个包,每个 go 应用程序都应该包含一个名为 main 的包

使用 import 关键字导入一个包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import "fmt"
import "os"

// 可将多个导入放在同一个括号中
// import (
// "fmt"
// "os"
// )

// 在导入时可以起别名
import fm "fmt"

func main() {
fm.Println("Hello World") // 访问包内的成员必须通过包访问,不能直接导入包内成员
}

访问级别

go 中只有公有和包私有两个访问级别,当成员使用大驼峰命名时,该成员为公有,当成员使用小驼峰命名时,该成员为包私有

1
2
3
4
5
6
7
8
9
package pack1

var privateVariable = 10

var PublicVariable = 90

func privateFunction() {}

func PublicFunction() {}

值类型与引用类型

go 中的 intfloatboolstring 这些基本类型都是值类型,不可变,在赋值时进行拷贝赋值,值类型的值存储在栈中

引用类型用于复杂数据,使用存储在栈上的指针指向存储在堆中的数据,引用类型赋值时拷贝引用

以上模式与 java 基本相同

go 支持指针类型,属于引用类型,可以获取一个变量的指针(内存地址),可以通过指针修改值,但不能进行指针运算

格式化输出

go 中通过 fmt 包实现格式化输出,主要使用以下函数

函数 功能
fmt.Print() 直接输出参数,参数间无分隔符,末尾无换行
fmt.Println() 输出参数,参数间自动加空格,末尾强制加换行(最常用的基础输出)
fmt.Printf() 按自定义格式输出(核心格式化函数),支持格式化动词,末尾无默认换行
fmt.Sprintf() 不直接输出,而是返回格式化后的字符串(可配合前三者间接输出)

格式化字符串中通过占位符实现格式化

占位符 说明 示例 输出
%v 按值的默认格式输出 fmt.Printf("%v", 123) 123
%+v 结构体输出字段名 fmt.Printf("%+v", user{Name:"Tom"}) {Name:Tom}
%#v 输出值的 Go 语法表示 fmt.Printf("%#v", "abc") "abc"
%T 输出值的类型 fmt.Printf("%T", 3.14) float64
%% 输出百分号本身 fmt.Printf("%.2f%%", 99.9) 99.90%
%d 十进制整数 fmt.Printf("%d", 0x10) 16
%b 二进制整数 fmt.Printf("%b", 8) 1000
%x 十六进制(小写) fmt.Printf("%x", 255) ff
%X 十六进制(大写) fmt.Printf("%X", 255) FF
%f 浮点数,默认 6 位小数 fmt.Printf("%f", 3.14) 3.140000
%.2f 浮点数,指定 2 位小数 fmt.Printf("%.2f", 3.1415) 3.14
%s 字符串/字节切片 fmt.Printf("%s", []byte("abc")) abc
%q 带引号的字符串 fmt.Printf("%q", "abc") "abc"
%t 布尔值 fmt.Printf("%t", true) true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func main() {
// 整数+进制转换
// 十进制:10,二进制:1010,十六进制:a
fmt.Printf("十进制:%d,二进制:%b,十六进制:%x\n", 10, 10, 10)

// 浮点数精度控制
// 默认精度:3.141593,保留2位:3.14,百分比:314.2%
pi := 3.1415926
fmt.Printf("默认精度:%f,保留2位:%.2f,百分比:%.1f%%\n", pi, pi, pi*100)

// 字符串+布尔
// 字符串:Go语言,带引号:"Go语言",布尔:false
fmt.Printf("字符串:%s,带引号:%q,布尔:%t\n", "Go语言", "Go语言", false)
}