文章目录
前言
- Drops of water outwear the stone
- 工作需要,入坑k8s和Tekton,既然要做吃螃蟹的人,Go学习势在必行
- 开坑Go,每周必更,flag立下
- 参考学习:GoByExample之快速入门
GoByExample
helloworld & value
- value使用参照Java
package main
import "fmt"
func main() {
fmt.Println("hello world")
fmt.Println("7.0/3.0 =", 7.0/3.0)
}
$ go run hello-world.go
hello world
7.0/3.0 = 2.3333333333333335
$ go build hello-world.go
$ ls
hello-world hello-world.go
$ ./hello-world
hello world
7.0/3.0 = 2.3333333333333335
variables & constants
func main() {
var a = "initial"
var b, c int = 1, 2 //声明多个变量
fmt.Println(b, c)
var d = true //会自动类型推断
var e int //未指定初始值,则为zero-valued(各类型的变量zero不同)
f := "apple" //等价于var f string = "apple"
}
package main
import (
"fmt"
"math"
)
const s string = "constant"
func main() {
fmt.Println(s)
const n = 500000000
const d = 3e20 / n //constant的表达式能以任意精度进行算术运算
fmt.Println(d)
fmt.Println(int64(d)) //数值常量没有类型,除非显式给予
fmt.Println(math.Sin(n)) //context给予,譬如显式强转,sin()以及函数调用
}
for & if/else
- 没有三元的if
package main
import "fmt"
func main() {
i := 1
for i <= 3 {
fmt.Println(i)
i = i + 1
}
for j := 7; j <= 9; j++ {
fmt.Println(j)
}
for { //死循环,除非break
fmt.Println("loop")
break
}
for n := 0; n <= 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
}
func main() {
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
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")
}
}
switch(有特殊用法)
package main
import (
"fmt"
"time"
)
func main() {
i := 2
fmt.Print("Write ", i, " as ")
switch i {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
}
switch time.Now().Weekday() {
case time.Saturday, time.Sunday: //逗号在一个case statement中分隔多个表达式
fmt.Println("It's the weekend")
default:
fmt.Println("It's a weekday")
}
//switch替代if/else,有点强啊
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
//特别关注,case类型,而不是value
whatAmI := func(i interface{}) { //discover the type of an interface value
switch t := i.(type) {
case bool:
fmt.Println("I'm a bool")
case int:
fmt.Println("I'm an int")
default:
fmt.Printf("Don't know type %T\n", t)
}
}
whatAmI(true)
whatAmI(1)
whatAmI("hey")
}
数组和slice
var a [5]int
fmt.Println("emp:", a) //默认 zero-valued, which for ints means 0s
a[4] = 100
fmt.Println("set:", a)
fmt.Println("get:", a[4])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5} //声明和初始化一起
fmt.Println("dcl:", b)
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
emp: [0 0 0 0 0]
set: [0 0 0 0 100]
get: 100
len: 5
dcl: [1 2 3 4 5]
2d: [[0 1 2] [1 2 3]]
slice
- Unlike arrays, slices are typed only by the elements they contain (not the number of elements)
s := make([]string, 3) //初始化方法,slice不用关注长度,只要关注元素类型
fmt.Println("emp:", s) //emp: [ ]
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("set:", s)
fmt.Println("get:", s[2])
fmt.Println("len:", len(s))
s = append(s, "d")
s = append(s, "e", "f") //[a b c d e f]
c := make([]string, len(s))
copy(c, s) //从s拷贝到c中
l := s[2:5] //左闭右开
l = s[:5]
l = s[2:]
t := []string{"g", "h", "i"} //初始化和声明一起,此处没有指定长度,不同于数组
twoD := make([][]int, 3) //3是行数
for i := 0; i < 3; i++ {
innerLen := i + 1
twoD[i] = make([]int, innerLen)
for j := 0; j < innerLen; j++ {
twoD[i][j] = i + j
}
}
//[[0] [1 2] [2 3 4]] 行数和列数不一定一致
Map
m := make(map[string]int)
m["k1"] = 7
m["k2"] = 13
fmt.Println("map:", m) //map: map[k1:7 k2:13]
v1 := m["k1"]
delete(m, "k2")
_, prs := m["k2"] //prs表示值是否存在
fmt.Println("prs:", prs)
n := map[string]int{"foo": 1, "bar": 2} //声明和初始化一起
fmt.Println("map:", n)
range
nums := []int{2, 3, 4}
for i, num := range nums { //i为索引,num为对应的value
if num == 3 {
fmt.Println("index:", i)
}
}
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
//a -> apple
//b -> banana
for k := range kvs {
fmt.Println("key:", k) //iterate over just the keys of a map
}
//key: a
//key: b
for i, c := range "go" {
fmt.Println(i, c)
}
//0 103
//1 111
Function
func plusPlus(a, b, c int) int {
return a + b + c
}
//等价
func plusPlus(a int, b int, c int) int {
return a + b + c
}
func vals() (int, int) {
return 3, 7
}
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
nums := []int{1, 2, 3, 4}
sum(nums...)
closures(匿名函数)
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
//intSeq函数的返回值为一个函数
//The returned function closes over the variable i to form a closure
func main() {
//We call intSeq, assigning the result (a function) to nextInt.
//This function value captures its own i value,
//which will be updated each time we call nextInt.
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
//To confirm that the state is unique to that particular function
//create and test a new one.
newInts := intSeq()
fmt.Println(newInts())
}
1
2
3
1
指针
- 函数传递是值传递
func zeroval(ival int) {
ival = 0
}
func zeroptr(iptr *int) {
*iptr = 0
}
func main() {
i := 1
fmt.Println("initial:", i) //1
zeroval(i)
fmt.Println("zeroval:", i)//1
zeroptr(&i)
fmt.Println("zeroptr:", i)//0
fmt.Println("pointer:", &i)//0x42131100
}
- *ptr负责从地址解析到value
- &i:取变量地址
struct(类比Java的class)
- typed collections of fields:有数据类型的变量集合
- grouping data together to form records: 整合数据来形成records
type person struct {
name string
age int
}
func newPerson(name string) *person {
p := person{name: name}
p.age = 42
return &p
}
person{"Bob", 20}
person{name: "Alice", age: 30}
person{name: "Fred"} //未复制的field默认为zero-valued
&person{name: "Ann", age: 40}
newPerson("Jon") //创建struct封装在函数中
s := person{name: "Sean", age: 50}
s.name
sp := &s
sp.age //指针会自动解析,同上文
sp.age = 51
sp.age
methods & interfaces
methods
- 可定义在struct上
- 使用指针可以避免拷贝实际值以及改变想改变的参数
use a pointer receiver type to avoid copying on method calls or to allow the method to mutate the receiving struct
-
Go语言在调用方法时自动将值和指针类型相互转换
Go automatically handles conversion between values and pointers for method calls.
type rect struct {
width, height int
}
func (r *rect) area() int { //a receiver type of *rect
return r.width * r.height
}
func (r rect) perim() int { //a value receiver
return 2*r.width + 2*r.height
}
func main() {
r := rect{width: 10, height: 5}
fmt.Println("area: ", r.area())
fmt.Println("perim:", r.perim())
rp := &r
fmt.Println("area: ", rp.area())
fmt.Println("perim:", rp.perim())
}
area: 50
perim: 30
area: 50
perim: 30
interface
- 组织关联的方法
package main
import (
"fmt"
"math"
)
type geometry interface {
area() float64
perim() float64
}
type rect struct {
width, height float64
}
type circle struct {
radius float64
}
//struct实现接口内的所有方法
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
//struct实现接口内的所有方法
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}
//类似多态
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}
measure(r)
measure(c)
}
Errors(重点)
-
根据惯例,errors是最后的返回值,且是内置的interface
-
通过显式,独立的返回值处理,不同于Java的exception和C语言中过载的单个result/error值
the overloaded single result / error value
-
好处在于可以统一处理函数,无论函数是否返回error
-
关注自定义Errors
package main
import (
"errors"
"fmt"
)
func f1(arg int) (int, error) {
if arg == 42 {
return -1, errors.New("can't work with 42")
//通过errors.New函数来构建一个basic的error值
}
return arg + 3, nil
//nil表示没有error
}
//通过实现Error()方法来自定义errors
type argError struct {
arg int
prob string
}
func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
if arg == 42 {
return -1, &argError{arg, "can't work with it"}
//&argError{arg, "can't work with it"}构造struct并对应赋值
}
return arg + 3, nil
}
func main() {
for _, i := range []int{7, 42} {
if r, e := f1(i); e != nil {
fmt.Println("f1 failed:", e)
} else {
fmt.Println("f1 worked:", r)
}
}
for _, i := range []int{7, 42} {
if r, e := f2(i); e != nil {
fmt.Println("f2 failed:", e)
} else {
fmt.Println("f2 worked:", r)
}
}
//If you want to programmatically use the data in a custom error, you’ll need to get the //error as an instance of the custom error type via type assertion.
//关注类型声明的转化语法
_, e := f2(42)
if ae, ok := e.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
}