Go语言基础 | 青训营

80 阅读8分钟

变量

声明方式:

  • var 名称 类型 = 值
  • var 名称 = 值
  • var 名称 类型
  • 名称 := 值 (:=是新建的意思,变量名不可以是定义过的)
var b,c int = 1,2
var a = "xdcfuih"
var d float32
e := float64(d)

常量

var改为const

分支

if-else:

和C或者C++类似,但if后面没有括号,且语句必须用大括号括起来,不能像C或者C++ -样,直接把if里面的语句同行

if 7%2==0 {
    fmt.Println("7 is even")
} else {
    fmt.Println("7 is odd" )
}

switch:

和C或者C++类似,但switch后面没有括号,且case不会连续执行,不需要break,相比C或者C++,go的switch功能更强大,可以使用任意的变量类型,甚至可以用来取代任意的if else语句--在switch后面不加任何的变量,然后在case里面写条件分支。这样代码相比用多个if else代码逻辑会更为清晰。

t := time.Now()
switch {
    case t.Hour( ) < 12:
        fmt.Println( "It's before noon" )
    default:
        fmt.Println("It's after noon")
}

循环

没有while,do-while,只有for,和C或者C++类似,但for后面没有括号

for j=7;j<9;j++ {
    fmt.Println(j)
}

数组

  • var 名称 类型
  • var 名称 = 类型{值}
  • 名称 := 类型{值}
var a [5]int
a[0] = 8b := []int{0,1,2,3,4}
b := [5]int{0,1,2,3,4}
​
var c = []int{0,1,2,3,4}
var c = [5]int{0,1,2,3,4}
​
//但不可以
var a []int//默认长度为0
a[0] = 8//重复啰嗦
var c []int = []int{0,1,2,3,4}

切片

切片不同于数组,可以任意更改长度,有更多丰富的操作。 用make来创建一个切片, 使用append来追加元素,必须把append的结果赋值为原数组。 slice的原理实际上是存储一个长度,加一个指向数组的指针,在你执行append操作的时候,如果容量不够的话,会扩容并且返回新的slice。 slice拥有像python一样的切片操作,不过不同于python,这里不支持负数索引

s := make([]string3)
s[0] = "a"
s[1] = "b"
s = append(s,"d")
s = append(s, "e""f")
fmt.Println(s) // [a b   d e f]
​
c := make([]stringlen(s))
copy(c,s)
fmt.Println(c) // [a b   d e f]
fmt.Println(s[2:5]) // [  d e]
fmt.Println(s[:5]) // [a b   d e]
fmt.Println(s[2:]) // [  d e f]

map

可以用make来创建一个空 map,这里会需要两个类型,第一个是 key的类型,这里是string;另-个是value的类型,这里是int。

我们可以从里面去存储或者取出键值对。 可以用delete从里面删除键值对。

m := make( map[string]int )
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
delete(m,"one")

ok可以用来判断在不在map里

r对应这个键在键值对里的值

fmt.Println(m["unknow"]) // 0
r,ok := m["unknow"]
fmt.Println(r,ok) // 0 false

range

对slice或map,我们可以range来快速遍历,这样代码能够更加简洁。

对于数组会返回两个值,第1个是索引,第二个是对应位置的值;对map会返回两个值,第1个是key,第二个是value

m := map[string]string{"a": "A","b": "B"}
for k, V := range m {
    fmt.Println(k,v) //a A;b B
}

如果我们不需要key或索引,可用下划线忽略

m := map[string]string{"a": "A", "b": "B"}
for _, v := range m {
    fmt.Println("value", v) //value A;value B
}

否则出来的是key或索引

m := map[string]string{"a": "A", "b": "B"}
for result := range m {
    fmt.Println(result) //a;b
}

函数

Golang 和其他很多语言不一样的是,变量类型是后置的。

Golang的函数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二个值是一个错误信息。

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

指针

go里面也支持指针,但相比C和C++支持的操作很有限,指针的一个主要用途就是对于传入参数进行修改。

func add2(n int) {
    n+=2
}
func add2ptr(n *int) {
    *n+=2
}
func main( ) {
    n:=5
    add2(n)
    fmt.Println(n) // 5
    add2ptr(&n)
    fmt.Println(n) // 7
}

结构体

结构体是带类型的字段的集合。

我们可以用结构体的名称去初始化一个结构体变量,构造的时候需要传入每个字段的初始值。也可以用键值对的方式去指定初始值,这样可以只对一部分字段进行初始化。

type user struct {
    name string
    password string
}
​
a := user{name: "wang", password: "1024"}
b := user{"wang""1024"}
C := user{name: "wang"}
C.password = "1024"
var d user
d.name = "wang"
d.password = "1024" 

结构体支持指针,这样能够实现对于结构体的修改,也可以在某些情况下避免一些大结构体的拷贝开销。带指针的话,那你那么你就可以对这个结构体去做修改。如果你不带指针的话,那你实际上操作的是一个拷贝,你就无法对结构体进行修改。

fmt.PrintIn(a, b,C, d)// {wang 1024} {wang 1024} {wang 1024} {wang 1024}
fmt. Println( checkPassword(a, "haha")) // false
fmt. Println( checkPassword2(&a,"haha")) // false//查找是一样的
func checkPassword(u user, password string) bool {
    return u. password== password
}
​
func checkPassword2(u *user, password string) bool {
    return u. password == password
}

在Golang里面可以为结构体去定义一些方法,类似其他语言里面的类成员函数。比如这里,我们把上面一个例子的checkPassword的实现,从一个普通函数,改成了结构体方法。这样用户可以像 a.checkPasswordl("xx")这样去调用。具体的代码修改,就是把第一个参数, 加上括号,写到函数名称前面。

func (u user) checkPassword( password string) bool {
    return u. password. == password
}
func (u *user) resetPassword( password string) {
    u. password = password 
}
func main( ) {
    a := user{name: "wang", password: "1024"}
    a. resetPassword( "2048" )
    fmt.Println(a. checkPassword( "2048")) // true
}

错误处理

错误处理在go语言里面使用一个单独的返回值来传递错误信息。 不同于Java使用的异常。go语言能够很清晰地知道哪个函数返回了错误,并且能用简单的if else来处理错误。 我们可以在函数的返回值类型里面,后面加一个error,就代表这个函数可能会返回错误。在函数实现的时候,return 需要同时return 两个值,要么就是如果出现错误的话,那么可以return nil和一个error。如果没有的话,那么返回原本的结果和nil。

package main
​
import (
    "errors"
    "fmt" 
)
​
type user struct {
    name string
    password string
}
​
func findUser(users []user, name string) (V *user, err error) {
    for _,U:=rangeusers{
        if u.name == name {
            return &u,nil
        }
    }
    return nil,errors.New("not found" )
}
​
func main() {
    u,err := findUser([]user{{"wang""1024"}}, "wang" )
    if err!=nil {
        fmt.Println(err)
        return
    }
    fmt.Println(u.name) // wang
    
    if u, err := findUser([]user{{"wang""1024"}}, "li"); err != nil {
        fmt.Println(err) // not found
        return
    } else {
        fmt. Println(u. name)
    }
}

字符串

在标准库strings包里面有很多常用的字符串工具函数。

在标准库的FMT包里面有很多的字符串格式相关的方法,比如printf这个类似于C语言里面的print函数。不同的是,在go语言里面可以很轻松地用%v来打印任意类型的变量,而不需要区分数字和字符串。%v打印任意变量结果,%+v打印详细结果,%#V 则更详细。%.数字f打印位数固定的浮点数。

p := point{12}
fmt.Printf("p=%v\n",p) // p={1 2}
fmt.Printf("p=%+v\n",p) // p={x:1 y:2}
fmt.Printf("p=%#v\n",p) // p=main. point{x:1, y:2}
f := 3.141592653
fmt.Println(f)//3. 141592653
fmt.Printf("%.2f\n",f) // 3.14

JSON处理

go语言里面的JSON操作非常简单,对于一个已有的结构体,我们可以什么都不做,只要保证每个字段的第一个字母是大写 ,也就是表示其是公开字段。那么这个结构体就能用JSON.marshaler去序列化,变成一个JSON的字符串。序列化之后的字符串也能够用JSON.unmarshaler反序列化到一个空的变量里面。 这样默认序列化出来的字符串的话,它的风格是大写字母开头,而不是下划线。我们可以在后面用json tag等语法来去修改输出JSON结果里面的字段名。

type userInfo struct {
    Name string
    Age int `json:"age"`
    Hobby []string
}
​
func main( ) {
    a := userInfo{Name: "wang”, Age: 18,Hobby: []string{"Golang", "TypeScript"}}
    buf,err := json.Marshal(a)
    if err!=nil{
        panic(err)
    }
    fmt.Println(string(buf)) //{"Name”: "wang", "age”:18, "Hobby":["Golang","TypeScript"]}
    var b userInfo
    err = json.Unmarshal(buf,&b)
    if err!=nil{
        panic(err)
    }
    fmt.Printf("%+v\n",b) //{Name: wang,Age:18, Hobby:[Golang TypeScript]}
}

时间处理

在标准库time包里面有很多常用的时间处理工具函数。最常用的就是time.now()来获取当前时间,也可以用time.date去构造一个带时区的时间, 构造完的时间。上面有很多方法来获取这个时间点的年月日小时分钟秒,然后也能用.sub去对两个时间进行减法,得到一个时间段。 时间段又可以去得到它有多少小时,多少分钟、多少秒。在和某些系统交互的时候,我们经常会用到时间戳。那可以用.UNIX来获取时间戳。

数字解析

关于字符串和数字类型之间的转换都在strconv这个包下,这个包是string convert这两个单词的缩写。 可以用parseInt或者parseFloat 来解析一个字符串。

进程信息

在标准库os包里面有很多常用的进程信息工具函数。