【青训营】go语言入门

118 阅读4分钟

go语言基础语法

变量

var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"

1.var关键字

go语言声明变量的一般形式是使用var关键字,name是变量名,type是变量的类型。需要注意的是,go语言和许多编程语言不同,它在声明变量时是将变量的类型放在变量的名称之后。

var b, c int = 1, 2
  1. =是赋值,:=是声明变量并赋值
var a
a = 100

var b = 100

var c int  = 100

d := 100 // := 是声明并赋值,并且系统自动推断类型,不需要var关键字
//会报错,重复声明变量a
var a int
a := 1
  1. float32和float64 float32,也即我们常说的单精度,存储占用4个字节,32位,其中1位用来表示符号,8位用来表示指数,剩下的23位表示尾数。 float64,也即我们常说的双精度,存储占用8个字节,64位,其中1位用来表示符号,11位用来表示指数,剩下的52位表示尾数。

float32.png

import "fmt"

var myFloat01 float32 = 100000182
var myFloat02 float32 = 100000187

func main() {
    fmt.Println("myfloat: ", myFloat01)   
    fmt.Println("myfloat: ", myFloat01 + 5)
    fmt.Println(myfloat02 == myfloat01 + 5)   //false
}

由于精度问题,第八位无法表示,所以运算后第七位的值,就会变得不精确。

  1. rune go语言的编码是按照UTF-8编码规则进行编码的,所以如果我们按照一个个字节的方式去处理中文字符串会导致乱码。所以go语言引进了rune的概念(其实是int32类型的别名)。在我们对字符串进行处理的时候只需要将字符串通过range去遍历,会按照rune为单位自动去处理。

判断语句

if 7%2 == 0 {
    ...
} else {
    ...
}

go语言中的判断语句与java类似,不同的是go语言的if语句后面没有括号,并且后面的大括号是必须要写的不能省略。

循环

func main() {
    i := 1
    for {
        ...
        break
    }
    for j := 7; j < 9; j++ {
        ...
    }
    for i <= 3 {
        ...
        i += 1
    }
}

go里面只有for一种循环。最简单的for循环就是在for后面什么都不写,代表一个死循环。

switch语句

func main() {
    a := 2
    switch a {
    case 1:
        ...
    case 2:
        ...
    case 3:
        ...
    case 4, 5:
        ...
    default:
        ...
    }
    
    t := time.Now()
    switch {
    case t.Hour() > 12:
        ...
    default:
        ...
    }
}

在java里,switch case如果不加break的话就会继续往下跑完所有的case,在go语言里面是不用加break的。 go语言的switch可以使用任意的变量类型,甚至可以用来取代if else语句,可以在switch后面不加任何的变量,然后在case里面写条件分支,这样代码会比多个if else更清晰。

切片

func main() {
    s := make([]string, 3)
    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    
    s = append(s, "d)
    s = append(s, "e", "f")
    
    s[2, 5]  // [c d e]
}

切片不同于数组,可以任意更改长度,我们可以用make来创建一个切片,使用append来追加元素。注意append用法,必须把append结果赋值为原数组。 slice拥有和python一样的切片操作,比如这个代表取出第二个到第五个位置的元素,不包括第五个元素。这里不支持负数索引

map

func main() {
    m := make(map[string]int)
    m["one"] = 1
    m["two"] = 2
    
    m2 := map[string]int{"one" : 1, "two", 2}
    var m3 = map[string]int{"one" : 1, "two", 2}
}

map(哈希表),我们可以用make创建一个空map,这里会需要两个类型,第一个是那个key的类型,这里是string,另一个是value的类型,这里是int。 golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。

range

func main() {
    nums := []int{2, 3, 4}
    sum := 0
    for i, num := range nums {
        sum += num
        if num == 2 {
            ...
        }
    }
}

对于一个slice或者一个map的话,我们可以用range来快速遍历,这样代码能够更加简洁。range遍历的时候,对于数组会返回两个值,第一个是索引,第二个是对应位置的值,如果我们不需要索引的话,我们可以用下划线来忽略。

函数

func exists(m map[string]string, k string) (v string, ok bool) {
    v, ok = m[k]
    return v, ok
} 

golang的变量类型是后置的,返回类型也是如此。golang里面的函数原生支持返回多个值,在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二个值的一个错误信息。

结构体方法

type user struct {
    name string
    password string
}

func (u user) checkPassword(password string) bool {
    return u.password == password
}

func (u *user) resetPassword(password string) {
    u.password = password
}

类似于类成员函数,如果不带指针,实际上操作的是一个拷贝,无法对结构体进行修改

错误处理

func findUser(users[] user, name string) (v *user, err error) {
    for _, u := range users {
        if u.name == name {
            return &u, nil
        }
    }
    return nil, errors.New("not found")
}

不同于java里的异常,go语言的处理方式,能够很清晰地知道哪个函数返回了错误,并且能用简单地if else来处理。