Go Roadmap-Basics
简介:Github star No.6 学习路线 Go 中译版
Learn the Basics
Go特点:静态类型,运行速度快,编译语言,编译速度快,自动垃圾回收,没有类和对象,没有继承关系。
example:
go
package main
import ("fmt")
func main() {
fmt.Println("Hello World!")
}
Basic Syntax
基本语法:包申明、导包、函数、语句。
上面的代码块讲解:
- 属于main包
- 导入了fmt这个包
- 空行更可读
- func main(){}是函数
- fmt.Println()是fmt包里的函数,可以打印文字。
基本语句:fmt.Println("Hello World!")
敲击enter键就可以结束一行(不用;)
所以:"{"不可以在一行的开头
Variables in Go
最常用变量类型:int float32 string bool
创建变量:
- 用var关键字
go
var name type = value//不加tpye也可以推断
- 用:=标志
go
name := value
tips:":="和auto类似,不分配值的时候不能用。
并且只能在函数内使用。var可以在函数外面。
变量的自动初始化:
string初始为""
int初始为0
bool初始为false
Data Types
go
package main
import ("fmt")
func main() {
var a bool = true // Boolean
var b int = 5 // Integer
var c float32 = 3.14 // Floating point number
var d string = "Hi!" // String
fmt.Println("Boolean: ", a)
fmt.Println("Integer: ", b)
fmt.Println("Float: ", c)
fmt.Println("String: ", d)
}
For Loop
go只有一种循环体,就是for循环。
三内容循环:
go
sum := 0
for i := 1; i < 5; i++ {
sum += i
}
fmt.Println(sum) // 10 (1+2+3+4)
区别在于:没有() 没有int 用的是:=。
while循环:
go
n := 1
for n < 5 {
n *= 2
}
fmt.Println(n) // 8 (1*2*2*2)
无限循环:(没有终止条件)
go
sum := 0
for {
sum++ // repeated forever
}
fmt.Println(sum) // never reached
For-each range循环:
go
strings := []string{"hello", "world"}
for i, s := range strings {
fmt.Println(i, s)
}
go
0 hello
1 world
String iteration: runes or bytes:
go
for i, ch := range "日本語" {
fmt.Printf("%#U starts at byte position %d\n", ch, i)
}
go
U+65E5 '日' starts at byte position 0
U+672C '本' starts at byte position 3
U+8A9E '語' starts at byte position 6
Range
在For Loop中
Conditional Statements
if
if / else
switch case
go
x := true
if x {
fmt.Println(s)
}
go
if x == 100 {
fmt.Println("Japan")
} else {
fmt.Println("Canada")
}
go
if x == 50 {
fmt.Println("Germany")
} else if x == 100 {
fmt.Println("Japan")
} else {
fmt.Println("Canada")
}
Errors/Panic/Recover
go不靠stack traces,也不靠try/catch
而是靠函数的值返回,和其他数据类型一样。
Conditional Statements
go
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
Functions
问题引入:
定义和声明
返回名
多返回类型
不同的函数类型
函数是为解决特定问题的封装。
有个输入给个输出。
go
package main
import "fmt"
func SimpleFunction() {
fmt.Println("Hello World")
}
func main() {
SimpleFunction()
}
带参数函数:
go
package main
import "fmt"
func add(x int, y int) {
total := 0
total = x + y
fmt.Println(total)
}
func main() {
// Passing arguments
add(20, 30)
}
带返回值函数:
go
package main
import "fmt"
func add(x int, y int) int {
total := 0
total = x + y
return total
}
func main() {
// Accepting return value in varaible
sum := add(20, 30)
fmt.Println(sum)
}
return返回值可以不写特定变量。
return返回值可以是多值,直接写return就可以。
传地址给函数:
go
package main
import "fmt"
func update(a *int, t *string) {
*a = *a + 5 // defrencing pointer address
*t = *t + " Doe" // defrencing pointer address
return
}
func main() {
var age = 20
var text = "John"
fmt.Println("Before:", text, age)
update(&age, &text)
fmt.Println("After :", text, age)
}
Output
Before: John 20
After : John Doe 25
匿名函数:
匿名函数就是没有函数名的函数。
Packages
包就是Go最强大的部分
fmt Package math Package string Package
fmt:
print就是输出完不换行,println就是输出完换行。
scanf和printf和C一样,还得指定%d
math:
sqrt是开根号
cbrt是开三次根
go
func main() {
// find the square root
fmt.Println(math.Sqrt(25)) // 5
// find the cube root
fmt.Println(math.Cbrt(27)) // 3
// find the maximum number
fmt.Println(math.Max(21, 18)) // 21
// find the minimum number
fmt.Println(math.Min(21, 18)) // 18
// find the remainder
fmt.Println(math.Mod(5, 2)) // 1
}
strings:
在这里插入代码片
go
package main
import (
"fmt"
"strings"
)
func main() {
lower := strings.ToLower("GOLANG STRINGS")
fmt.Println(lower)
upper := strings.ToUpper("golang strings")
fmt.Println(upper)
stringArray := []string{"I love", "Go Programming"}
joinedString := strings.Join(stringArray, " ");
fmt.Println(joinedString)
}
go
Output
golang strings
GOLANG STRINGS
I love Go Programming
Type Casting
转化一个类型到另一个类型
go
i := int(32.987) // 转化到int类型
Go并不支持隐式类型转换(不同于C++)
并且从string转化为int时,可以用strconv包
go
package main
import (
"fmt"
"strconv"
)
func main() {
var s string = "42"
v, _ := strconv.Atoi(s) // convert string to int
fmt.Println(v) // 42
var i int = 42
str := strconv.Itoa(i) // convert int to string
fmt.Println(str) // 42
}
Type Inference
尽管时静态类型,却不需要全都初始化定义的变量,
可以自动推断,通过右边的值。
go
package main
import "fmt"
func main() {
// Multiple variable declarations with inferred types
var firstName, lastName, age, salary = "John", "Maxwell", 28, 50000.0
fmt.Printf("firstName: %T, lastName: %T, age: %T, salary: %T\n",
firstName, lastName, age, salary)
}
# Output
firstName: string, lastName: string, age: int, salary: float64
如果在函数体内,最好还用;=
go
package main
import "fmt"
func main() {
name := "Rajeev Singh"
age, salary, isProgrammer := 35, 50000.0, true
fmt.Println(name, age, salary, isProgrammer)
}
# Output
Rajeev Singh 35 50000 true
Arrays
就是一组相同元素的集合。
go
package main
import "fmt"
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
}
go
Hello World
[Hello World]
[2 3 5 7 11 13]
Slices
类似于arrays,但是更强大,更灵活。
也是存储多个类型相同的值。
但是slice的长度可以生长和缩小。(形象)
语法:
go
myslice := []int{}
上述这就是0长度,0容量的slice。
也可以初始化:
go
myslice := []int{1,2,3}
怎么得到长度和容量呢?
用如下两个函数:len()和cap()
go
myslice2 := []string{"Go", "Slices", "Are", "Powerful"}
fmt.Println(len(myslice2))
fmt.Println(cap(myslice2))
fmt.Println(myslice2)
上述的len就是4,而cap也是4。
怎么从一个数组创建slice呢?
go
package main
import ("fmt")
func main() {
arr1 := [6]int{10, 11, 12, 13, 14,15}
myslice := arr1[2:4]
fmt.Printf("myslice = %v\n", myslice)
fmt.Printf("length = %d\n", len(myslice))
fmt.Printf("capacity = %d\n", cap(myslice))
}
go
Result:
myslice = [12 13]
length = 2
capacity = 4
解释:【2:4】指的是左闭右开区间的,所以就是要索引为2和3的数组中的数字,所以长度是2,但是因为切隔切了从2开始后面所有的,所以容量是4。
也可以用make()函数来创建slice:
go
myslice1 := make([]int, 5, 10)
fmt.Printf("myslice1 = %v\n", myslice1)
fmt.Printf("length = %d\n", len(myslice1))
fmt.Printf("capacity = %d\n", cap(myslice1))
Maps
maps是用于存放键值对组合的,无序。
map的默认值是nil。
go
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964"}
b := map[string]int{"Oslo": 1, "Bergen": 2, "Trondheim": 3, "Stavanger": 4}
fmt.Printf("a\t%v\n", a)
fmt.Printf("b\t%v\n", b)
}
Result:
a map[brand:Ford model:Mustang year:1964]
b map[Bergen:2 Oslo:1 Stavanger:4 Trondheim:3]
也可以用make()函数创建map
go
package main
import ("fmt")
func main() {
var a = make(map[string]string) // The map is empty now
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
// a is no longer empty
b := make(map[string]int)
b["Oslo"] = 1
b["Bergen"] = 2
b["Trondheim"] = 3
b["Stavanger"] = 4
fmt.Printf("a\t%v\n", a)
fmt.Printf("b\t%v\n", b)
}
想写一个空map,就是得用make()函数。
其他的var 或者:=会导致运行错误。
go
package main
import ("fmt")
func main() {
var a = make(map[string]string)
var b map[string]string
fmt.Println(a == nil)
fmt.Println(b == nil)
}
Result:
false
true
map可以用什么类型的数据做键呢?
Booleans
Numbers
Strings
Arrays
Pointers
Structs Interfaces (as long as the dynamic type supports equality)
获取map元素:
go
map_name[key]
更新、添加map元素:
和创建是一样的。
删除map元素:
go
delete(map_name, key)
查找特定元素:
go
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964", "day":""}
val1, ok1 := a["brand"] // Checking for existing key and its value
val2, ok2 := a["color"] // Checking for non-existing key and its value
val3, ok3 := a["day"] // Checking for existing key and its value
_, ok4 := a["model"] // Only checking for existing key and not its value
fmt.Println(val1, ok1)
fmt.Println(val2, ok2)
fmt.Println(val3, ok3)
fmt.Println(ok4)
}
Result:
Ford true
false
true
true
maps are references(类似于return by references)
如果两个map都是同一个哈希表,那么修改一个,另一个也会变。
迭代输出maps元素:
用range
来迭代输出,但是是无序的。因为maos本身是无序的数据结构。
go
package main
import ("fmt")
func main() {
a := map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}
for k, v := range a {
fmt.Printf("%v : %v, ", k, v)
}
}
Result:
two : 2, three : 3, four : 4, one : 1,
如果想要有序,也可以的,使用如下的方式:
go
package main
import ("fmt")
func main() {
a := map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}
var b []string // defining the order
b = append(b, "one", "two", "three", "four")
for k, v := range a { // loop with no order
fmt.Printf("%v : %v, ", k, v)
}
fmt.Println()
for _, element := range b { // loop with the defined order
fmt.Printf("%v : %v, ", element, a[element])
}
}
Result:
two : 2, three : 3, four : 4, one : 1,
one : 1, two : 2, three : 3, four : 4,
make
make()函数可以创建、初始化slices,
maps、channels。
go
var intSlice = make([]int, 10) // when length and capacity is same
var strSlice = make([]string, 10, 20) // when length and capacity is different
go
var employee = make(map[string]int)
employee["Mark"] = 10
employee["Sandy"] = 20
make()函数创建channels:
channels是goroutines相互通信的中间件。
goroutines可以并发,相互之间要通信,共享资源。
go
package main
import "fmt"
func main() {
// create channel of integer type
number := make(chan int)
// access type and value of channel
fmt.Printf("Channel Type: %T\n", number)
fmt.Printf("Channel Value: %v", number)
}
Output
Channel Type: chan int
Channel Value: 0xc00007a060
structs
用户自定义类型,就是类似C++的struct
go语言没有继承,没有super
上图是structs使用。