1.1 Go学习笔记之基本语法

前言

  • 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)
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值