Quickly Master Go’s Distinctive Syntax—Basic Syntax
0x00 Background — Intended primarily for developers who want to learn Golang quickly and at low cost, focusing on the syntax, usage, and concepts that distinguish it from other languages. Familiarity with a backend language is recommended, as programming concepts are transferable; experienced developers can quickly get started by learning Go’s unique features. Each topic below is explained through comments alongside code examples.
Read in Chinese→0x00 Background
-
This is mainly intended for developers who want to learn Golang quickly and at low cost. It focuses primarily on the syntax, usage, and concepts that distinguish it from other languages.
-
Ideally, you should already be familiar with a backend language, which will allow you to learn and get started with Go quickly.
-
Because programming concepts are transferable, developers who are already proficient in one language can get started quickly as long as they learn the distinctive features of the language.
-
The following topics are not explained separately. Instead, the relevant details are included in comments alongside the code. I think this works quite well; the code examples should make them easy to understand.
0x01 Basic Go Syntax
Note that Go has a very special rule:
Every declared variable must be used later. Declaring a variable without using it is not allowed. Therefore, if the following code fails to run, first check whether any variables have been declared but not used.
0x011 Basic Function Format: (Braces and Semicolons)
package main //程序的包名
import (
"fmt"
"time"
)
//main函数
func main() { //函数的{ 一定是 和函数名在同一行的,否则编译错误
//golang中的表达式,加";", 和不加 都可以,建议是不加
fmt.Println(" hello Go!")
}
0x012 Four Ways to Declare Variables
package main
import (
"fmt"
)
//声明全局变量 方法一、方法二、方法三是可以的
var gA int = 100
var gB = 200
//用方法四 只能局部变量,在函数体内
// := 只能够用在 函数体内来声明
//gC := 200
func main() {
//方法一:声明一个变量 默认的值是0
var a int
//方法二:声明一个变量,初始化一个值
var b int = 100
//方法三:在初始化的时候,可以省去数据类型,通过值自动匹配当前的变量的数据类型
var c = 100
var cc = "abcd"
//方法四:(常用的方法) 省去var关键字,直接自动匹配
e := 100
f := "abcd"
g := 3.14
// 声明多个变量
var xx, yy int = 100, 200
var kk, ll = 100, "Aceld"
//多行的多变量声明
var (
vv int = 100
jj bool = true
)
fmt.Println("自行输出吧")
}
0x013 Multiple Return Values from Functions
package main
import "fmt"
//一般返回
func foo1(a string, b int) int {
fmt.Println("a = ", a)
fmt.Println("b = ", b)
c := 100
return c
}
//返回多个返回值,匿名的
func foo2(a string, b int) (int, int) {
fmt.Println("a = ", a)
fmt.Println("b = ", b)
return 666, 777
}
//返回多个返回值, 有形参名称的
func foo3(a string, b int) (r1 int, r2 int) {
fmt.Println("---- foo3 ----")
fmt.Println("a = ", a)
fmt.Println("b = ", b)
//r1 r2 属于foo3的形参, 初始化默认的值是0
//r1 r2 作用域空间 是foo3 整个函数体的{}空间
fmt.Println("r1 = ", r1)
fmt.Println("r2 = ", r2)
//给有名称的返回值变量赋值
r1 = 1000
r2 = 2000
return
}
//有相同的返回类型
func foo4(a string, b int) (r1, r2 int) {
fmt.Println("---- foo4 ----")
fmt.Println("a = ", a)
fmt.Println("b = ", b)
//给有名称的返回值变量赋值
r1 = 1000
r2 = 2000
return
}
func main() {
c := foo1("abc", 555)
fmt.Println("c = ", c)
ret1, ret2 := foo2("haha", 999)
fmt.Println("ret1 = ", ret1, " ret2 = ", ret2)
ret1, ret2 = foo3("foo3", 333)
fmt.Println("ret1 = ", ret1, " ret2 = ", ret2)
ret1, ret2 = foo4("foo4", 444)
fmt.Println("ret1 = ", ret1, " ret2 = ", ret2)
}
0x014 iota Can Only Be Used with const
package main
import "fmt"
//const 来定义枚举类型
const (
//可以在const() 添加一个关键字 iota, 每行的iota都会累加1, 第一行的iota的默认值是0
BEIJING = 10*iota //iota = 0
SHANGHAI //iota = 1
SHENZHEN //iota = 2
)
const (
a, b = iota+1, iota+2 // iota = 0, a = iota + 1, b = iota + 2, a = 1, b = 2
c, d // iota = 1, c = iota + 1, d = iota + 2, c = 2, d = 3
e, f // iota = 2, e = iota + 1, f = iota + 2, e = 3, f = 4
g, h = iota * 2, iota *3 // iota = 3, g = iota * 2, h = iota * 3, g = 6, h = 9
i, k // iota = 4, i = iota * 2, k = iota * 3 , i = 8, k = 12
)
func main() {
//常量(只读属性),常量是不允许修改的
const length int = 10
fmt.Println("length = ", length)
fmt.Println("BEIJIGN = ", BEIJING)
fmt.Println("SHANGHAI = ", SHANGHAI)
fmt.Println("SHENZHEN = ", SHENZHEN)
fmt.Println("a = ", a, "b = ", b)
fmt.Println("c = ", c, "d = ", d)
fmt.Println("e = ", e, "f = ", f)
fmt.Println("g = ", g, "h = ", h)
fmt.Println("i = ", i, "k = ", k)
// iota 只能够配合const() 一起使用, iota只有在const进行累加效果。
//var a int = iota
}
0x015 defer
This is similar to a Python decorator combined with finally; it runs after the function finishes executing.
package main
import "fmt"
func main() {
//写入defer关键字
defer fmt.Println("main end1")
defer fmt.Println("main end2")
fmt.Println("main::hello go 1")
fmt.Println("main::hello go 2")
}
//main::hello go 1
//main::hello go 2
//main end2
//main end1
0x016 Arrays and Loop Iteration
package main
import "fmt"
func printArray(myArray [4]int) {
//值拷贝
for index, value := range myArray {
fmt.Println("index = ", index, ", value = ", value)
}
myArray[0] = 111
}
func main() {
//固定长度的数组
var myArray1 [10]int
myArray2 := [10]int{1,2,3,4}
myArray3 := [4]int{11,22,33,44}
//for i := 0; i < 10; i++ 类似于C语言的常规遍历
for i := 0; i < len(myArray1); i++ {
fmt.Println(myArray1[i])
}
//使用range 遍历数组切片,返回值为 数组下标和值
for index, value := range myArray2 {
fmt.Println("index = ", index, ", value = ", value)
}
//查看数组的数据类型
fmt.Printf("myArray1 types = %T\n", myArray1)
fmt.Printf("myArray2 types = %T\n", myArray2)
fmt.Printf("myArray3 types = %T\n", myArray3)
printArray(myArray3)
for index, value := range myArray3 {
fmt.Println("index = ", index, ", value = ", value)
}
}
0x2 Slices
Assigning Slices
package main
import "fmt"
func printArray(myArray [4]int) {
//值拷贝
for index, value := range myArray {
fmt.Println("index = ", index, ", value = ", value)
}
myArray[0] = 111
}
func main() {
//固定长度的数组
var myArray1 [10]int
myArray2 := [10]int{1,2,3,4}
myArray3 := [4]int{11,22,33,44}
//for i := 0; i < 10; i++ {
for i := 0; i < len(myArray1); i++ {
fmt.Println(myArray1[i])
}
for index, value := range myArray2 {
fmt.Println("index = ", index, ", value = ", value)
}
//查看数组的数据类型
fmt.Printf("myArray1 types = %T\n", myArray1)
fmt.Printf("myArray2 types = %T\n", myArray2)
fmt.Printf("myArray3 types = %T\n", myArray3)
printArray(myArray3)
fmt.Println(" ------ ")
for index, value := range myArray3 {
fmt.Println("index = ", index, ", value = ", value)
}
}
Dynamic Array Slices
package main
import "fmt"
func printArray2(myArray []int) {
//引用传递
// _ 表示匿名的变量
for _, value := range myArray {
fmt.Println("value = ", value)
}
myArray[0] = 100
}
func main() {
myArray := []int{1,2,3,4} // 动态数组,切片 slice
fmt.Printf("myArray type is %T\n", myArray)
printArray2(myArray)
fmt.Println(" ==== ")
for _, value := range myArray {
fmt.Println("value = ", value)
}
}
Several Ways to Declare Slices
package main
import "fmt"
func main() {
//声明slice1是一个切片,并且初始化,默认值是1,2,3。 长度len是3
slice1 := []int{1, 2, 3}
//声明slice2是一个切片,但是并没有给slice分配空间
var slice2 []int
fmt.Printf("slice2: %v\n",slice2)
//slice1 = make([]int, 3) //开辟3个空间 ,默认值是0
//声明slice1是一个切片,同时给slice分配空间,3个空间,初始化值是0
//var slice1 []int = make([]int, 3)
//声明slice1是一个切片,同时给slice分配空间,3个空间,初始化值是0, 通过:=推导出slice是一个切片
// 常见
slice3 := make([]int, 3)
fmt.Printf("slice3: %v\n",slice3)
fmt.Printf("len = %d, slice = %v\n", len(slice1), slice1)
//判断一个silce是否为0
if slice2 == nil {
fmt.Println("slice2 是一个空切片")
} else {
fmt.Println("slice2 是有空间的")
}
}
The concepts of length and capacity here are different:
- Capacity is the specific number of elements for which the slice has allocated space.
- Length,
len, is the number of allocated positions that are already occupied.
Appending to a Slice
package main
import "fmt"
func main() {
var numbers = make([]int, 3, 5)
// 长度为3 容量为5 [0,0,0,空,空]
fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)
//向numbers切片追加一个元素1, numbers len = 4, [0,0,0,1], cap = 5
numbers = append(numbers, 1)
fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)
//向numbers切片追加一个元素2, numbers len = 5, [0,0,0,1,2], cap = 5
numbers = append(numbers, 2)
fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)
//向一个容量cap已经满的slice 追加元素,追加的数量为之前申请的5个,[0,0,0,1,2,2,0,0,0,0]
numbers = append(numbers, 3)
fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers), cap(numbers), numbers)
// len = 6, cap = 10, slice = [0 0 0 1 2 3]
// 不指定长度的slice
var numbers2 = make([]int, 3)
fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers2), cap(numbers2), numbers2)
// len = 3, cap = 3, slice = [0 0 0]
numbers2 = append(numbers2, 1)
fmt.Printf("len = %d, cap = %d, slice = %v\n", len(numbers2), cap(numbers2), numbers2)
// len = 4, cap = 6, slice = [0 0 0 1]
}
Slicing a Slice
This works the same way as slicing in Python.
package main
import "fmt"
func main() {
s := []int{1, 2, 3} //len = 3, cap = 3, [1,2,3]
//[0, 2)
s1 := s[0:2] // [1, 2]
fmt.Println(s1)
s1[0] = 100
fmt.Println(s)
fmt.Println(s1)
//copy 可以将底层数组的slice一起进行拷贝
s2 := make([]int, 3) //s2 = [0,0,0]
//将s中的值 依次拷贝到s2中
copy(s2, s)
fmt.Println(s2)
}
```Slice syntax:
| **Operation** | **Meaning** |
| --- | --- |
| **s\[n\]** | The item at index n in slice s |
| **s\[:\]** | The slice obtained from index 0 through len\(s\)-1 of slice s |
| **s\[low:\]** | The slice obtained from index low through len\(s\)-1 of slice s |
| **s\[:high\]** | The slice obtained from index 0 through high of slice s, len=high |
| **s\[low:high\]** | The slice obtained from index low through high of slice s, len=high-low |
| **s\[low:high:max\]** | The slice obtained from index low through high of slice s, len=high-low, cap=max-low |
| **len\(s\)** | The length of slice s, always \<=cap\(s\) |
| **cap\(s\)** | The capacity of slice s, always >=len\(s\) |
## 0x03 Maps
### Defining a Map```go
package main
import "fmt"
func main() {
//===> 第一种声明方式
//声明myMap1是一种map类型 key是string, value是string
var myMap1 map[string]string
if myMap1 == nil {
fmt.Println("myMap1 是一个空map")
}
//在使用map前, 需要先用make给map分配数据空间
myMap1 = make(map[string]string, 10)
myMap1["one"] = "java"
myMap1["two"] = "c++"
myMap1["three"] = "python"
fmt.Println(myMap1)
//===> 第二种声明方式,自动分配空间
myMap2 := make(map[int]string)
myMap2[1] = "java"
myMap2[2] = "c++"
myMap2[3] = "python"
fmt.Println(myMap2)
//===> 第三种声明方式
myMap3 := map[string]string{
"one": "php",
"two": "c++",
"three": "python",
}
fmt.Println(myMap3)
}
Using a Map
package main
import "fmt"
func printMap(tmpMap map[string]string) {
//cityMap 是一个引用传递
for key, value := range tmpMap {
fmt.Println("key = ", key)
fmt.Println("value = ", value)
}
}
func ChangeValue(cityMap map[string]string) {
cityMap["England"] = "London"
}
func main() {
cityMap := make(map[string]string)
//添加
cityMap["China"] = "Beijing"
cityMap["Japan"] = "Tokyo"
cityMap["USA"] = "NewYork"
//遍历
printMap(cityMap)
//删除
delete(cityMap, "China")
//修改
cityMap["USA"] = "DC"
ChangeValue(cityMap)
fmt.Println("-------")
//遍历
printMap(cityMap)
}