Go 语言入门指南:基础语法和常用特性解析 | 青训营

130 阅读9分钟

1.hello world

学习编程的第一件事就是输出**hello world** 。^-^

package main
import "fmt"
func main(){//大括号位置固定
fmt.Println("hello world")
}

2.变量

Go语言数据类型:(1)布尔型:bool (2) 数字类型:整型 int 和浮点型 float32、float64 (3) 字符串类型:string (4) 派生类型:a. 指针类型(Pointer)b.数组类型 c.结构化类型(struct) d.Channel 类型 e.函数类型 f.切片类型 g.接口类型(interface) h.Map 类型。

var是声明的关键字,声明变量有两个方式:(1)var name int = 10 (2)name := 10,类型要在变量名后。

多个变量声明:(1)var name1, name2 int = 20, 30var name1, name2 = 20, "hello" (2) name1, name2 := 10, "hello"

go语言中字符串是内置类型,可以用 + 拼接:name := "hello" + "world"

数字类型转换:var name1 float64 = 1.11415365949 name2 := int( name1 )

如果变量没有初始化,则默认为零值:(1) 布尔类型: false (2) 数字类型: 0 (3) 字符串类型: 空字符串 ( "" ) (4) 其他类型:nil 。

golang 的常量没有确定的类型,能够根据使用的上下文自动确定类型: const name1, name2 = 10, "hello"

golang中声明的局部变量必须在相同的代码块中使用它,全局变量是允许声明但不使用。

3.if-else

if后面没有括号,但可以在条件面前进行一些操作,换言之,if语句可以在条件表达式前执行一个简单的语句。

package main
import "fmt"
func main() {
    if name := 10; name > 10 {  //if-else括号位置固定
        fmt.Println("name > 10")
    } else {
        fmt.Println("name < 10")
    }
}

4.循环

go只有一种循环:for循环。去掉分号后,和while作用相同。

break: 中断循环 continue: 跳过当前循环,进入下一循环 goto: 转移到被标记的位置。

for 条件的起始值 ;循环条件;控制自变量改变

package main
import "fmt"
func main() {
    for i := 0; i <= 10; i++ {
        fmt.Println(i)
    }
    name := 5
    for name < 10 {
        fmt.Println(name)
        name++
    }
}

5.switch

Go语言中switch语句的case 自带 break 语句,匹配成功时停止。如果需要执行后面的 case,使用 fallthrough 。switch 的 case 后可以不为常量,为其他判断语句。因此Go语言中switch更为强大。

switch语句也可以在条件表达式前执行一个简单的语句。

switch不附加条件时 等价switch true

package main
import "fmt"
func main() {
    switch name := "hello"; name {
    case "ni hao":
        fmt.Println("ni hao")
    case "hello":
        fmt.Println("hello")
    default:
        fmt.Println("bye")
    }
}
​

6.数组

定义数组:将变量 a 声明为拥有 n 个整数的数组: var a = [n]int

初始化数组:(1) var a = [4]int{1,2,3,4} (2) a := [4]int{1,2,3,4}

注意:数组长度不可变,切片长度可变。

package main
import "fmt"
func main() {
    var a = [4]int{1, 2, 3, 4}
    fmt.Println(a[1])//2
    b := [4]int{1, 2, 3, 4}
    fmt.Println(b)//[1 2 3 4]
    var c [4]int
    c[1] = 9
    fmt.Println(c[1])   //9
    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)//2d: [[0 1 2] [1 2 3]]
}
​

7.切片

切片不存储任何数据,它只是描述了底层数组中的一段。更改切片的元素会修改其底层数组中对应的元素。

创建切片:(1) var a []int (2) a := make([]int, len, cap) (3) var a []int = make([]int, len, cap)

(len为切片长度,cap为切片容量(若不指定容量可省略)。切片的长度就是它所包含的元素个数。切片的容量是从它的第一个元素到其底层数组元素末尾的个数。)

初始化切片:(1) a := []int {1,2,3 } (2) a := 数组名[下标:上标] (切片下标的默认值为 0,上标的默认值切片的长度)。

切片的使用:var a []int = 数组名[1:4] (切片包括第一个元素,排除最后一个元素,该切片a包含 数组 中下标从 1 到 3 的元素)

len(a) 获取切片长度,cap(a) 获取切片容量。

切片的零值是 nilnil 切片的长度和容量为 0 且没有底层数组。

切片可用append追加元素,需要赋值回原切片:a = append(a, "world")

可以将一个切片的数值拷贝到另一个切片:copy(b,a) (将切片a的数值拷贝到切片b上)。

package main
​
import "fmt"func main() {
    s := make([]string, 3) //用make创建切片
    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("get:", s[2])  //c
    fmt.Println("len", len(s)) //3
​
    s = append(s, "d") //切片可用append追加元素,需要赋值回原切片
    s = append(s, "e", "f")
    fmt.Println(s) //[a b c d e f]
​
    c := make([]string, len(s)) //创建切片对应的长度
    copy(c, s)                  //拷贝数值
    fmt.Println(c)              //[a b c d e f]
​
    fmt.Println(s[2:5]) //[c d e]
    fmt.Println(s[:5])  //[a b c d e]
    fmt.Println(s[2:])  //[c d e f]
​
    good := []string{"gc", "o", "o", "d"}
    fmt.Println(good) //[g o o d]
}
​

8.map(映射)

创建map:(1)name := make(map[string]int) 用make创建空map,[ ] 内是key类型,[ ] 外右侧是value类型

(2) name := map[string]int{"one": 1, "two": 2}:= 赋值创建

(3) var name = map[string]int{"one": 1, "two": 2} 用var声明变量创建

在map中的操作:(1) 插入或修改元素:name[key] = value (2) 删除元素:delete (name, key)

通过双赋值检测某个key值是否存在:a,ok = name[key] ,若映射name中存在key值,ok为true,a为value值;否则 ok为false,a为0。

package main
​
import "fmt"func main() {
    m := make(map[string]int) //1.用make创建空map,[]内是key类型,[]外是value类型
    m["one"] = 1
    m["two"] = 2
    fmt.Println(m)           //map[one:1 two:2]
    fmt.Println(len(m))      //2
    fmt.Println(m["one"])    //1
    fmt.Println(m["unknow"]) //0
​
    r, ok := m["unknow"] //ok判断map内是否有key存在
    fmt.Println(r, ok)   //0 falsedelete(m, "one")                            //删除
    fmt.Println(m)                              //map[two:2]
    m2 := map[string]int{"one": 1, "two": 2}    //2.用:=创建
    var m3 = map[string]int{"one": 1, "two": 2} //3。用var创建
    fmt.Println(m2, m3)
​
}
​

9.range

for 循环的 range 形式可遍历切片或映:for i, j := range name

(1) 当使用 for 循环遍历切片时,每次迭代都会返回两个值。第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。

若只需要下标或元素值,可用将值赋予 _ :(1) for i, _ := range name,(2) for _, j := range name

若只需要下表,可直接省略第二个变量:for i := range name

(2) 当使用 for 循环遍历映射时,每次迭代都会返回两个值。第一个值为key值,第二个值为value值。

package main
​
import "fmt"func main() {
    nums := []int{2, 3, 4}
    sum := 0
    for i, num := range nums { //range对数组快速遍历返回两个值
        sum += num
        if num == 2 { //第一个值是索引,第二个值是对应位置的值
            fmt.Println("index: ", i, "num: ", num) //index:  0 num:  2
        }
    }
    fmt.Println(sum) //9
    m := map[string]string{"a": "A", "b": "B"}
    for k, v := range m { //第一个值是key,第二个值是value
        fmt.Println(k, v) //
    }
    for k := range m {
        fmt.Println("key", k)
    }
}
​

10.函数

Go语言函数格式:func name( 参数列表 ) 函数返回值类型

可以返回多个结果和错误信息:value, ok := name( 参数列表 )value为返回值,若信息正确,oktrue,否则okfalse

Go语言中,方法是一类带特殊的 接收者 参数的函数。方法接收者在自身的参数列表内,位于 func 关键字和方法名(相当于函数名)之间:func (接受者的名字 数据类型) name( 参数列表 ) 方法返回值类型,通过m.name( 参数 )来调用 ,这是和函数不同的地方 (m是以接收者数据类型命名的变量)。

11.指针

Go语言中的指针相对简单,取止符仍是&,指针的零值为 nil 。

指针的声明:var a *int

可以用指针来传入参数:func 函数名(a, b *int) int,这样可以直接更改传入的变量的值。

12.结构体

结构体是带类型的字段的集合,结构体格式:type name struct

结构体的初始化:(1) 用结构体的名称初始化结构体变量,传入每个字段的初始值 (2) 直接传入每个字段的初始值 (3) 可以只指定一部分的值初始化 (4) 未初始化的值,则自动初始化为空值,数字为0,字符串为空字符串 。

package main
​
import "fmt"// 结构体是带类型的字段的集合
type user struct {
    name     string
    password string
}
​
func main() {
    a := user{name: "wang", password: "1024"} //1.用结构体的名称初始化结构体变量,传入每个字段的初始值
    b := user{"wang", "1024"}//2.
    c := user{name: "wang"} //3.可以只指定一部分的值
    c.password = "1024"
    var d user      //4.未初始化,则自动初始化为空值,数字为0,字符串为空字符串
    d.name = "wang" //可以读取和写入字符串内容
    d.password = "1024"
    fmt.Println(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
}

13.结构体方法

可以为结构体类型定义方法,数据类型为声明的结构体名字。

package main
​
import "fmt"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 main() {
    a := user{name: "wang", password: "1024"}
    a.resetPassword("2048")
    fmt.Println(a.checkPassword("2048")) //true
}
​

14.错误处理

Go 语言通过内置的错误接口提供了非常简单的错误处理机制。

package main
​
import (
    "errors"
    "fmt"
)
​
type user struct {
    name     string
    password string
}
​
func finduser(users []user, name string) (v *user, err error) { //error说明这个函数可能返回错误
    //用简单的if-else处理错误
    for _, u := range users {
        if u.name == name {
            return &u, nil //没有错误出现,返回两个值,原本的结果和nil值
        }
    }
    return nil, errors.New("not found") //有错误出现
}
func main() {
    u, err := finduser([]user{{"wang", "1024"}}, "wang") //调用返回错误的函数,接收需2个变量
    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)
    }
}
​

15.字符串操作

a := "hello"

(1) 判断一个字符串内是否包含另一个字符串:strings.Contains(a, "hello") ,在a中查找是否有hello,返回truefalse

(2)字符串计数:strings.Count(a, "hello") ,在a中查找有几个hello,返回整型数据。

(3)前缀判断:strings.HasPrefix(a, "he") ,判断a中是否有he作为前缀,返回truefalse

(4)后缀判断:strings.HasSuffix(a, "llo") ,判断a中是否有llo作为后缀,返回truefalse

(5)查找某个字符串的位置:strings.Index(a, "ll") ,返回ll的位置。

(6)连接多个字符串:strings.Join([]string{"he", "llo"}, "-") ,用**-**将hello拼接。

(7)重复多个字符串:strings.Repeat(a, 2) ,将a复制两次实现。

(8)替换字符串中的字符:strings.Replace(a, "e", "E", -1) ,将a中的e替换成E

(9)指定字符分割字符串:strings.Split("-a-b-c", "-")-起分割作用,输出a b c

(10)将字符串转换成小写形式:strings.ToLower(a)

(11)将字符串转换成大写形式:strings.ToUpper(a)

(12)统计字符串的长度:len(a) 。中文的单位长度为3。

(13)去除字符串的首位空白:strings.TrimSpace(a)