golang 基础语法 第四篇

209 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1. switch

package main
​
import (
    "fmt"
    "os"
)
​
//从命令输入参数,在switch中进行处理func main() {
    //C: argc , **argv
    //Go: os.Args ==> 直接可以获取命令输入,是一个字符串切片 []string
    cmds := os.Args
​
    //os.Args[0] ==> 程序名字
    //os.Args[1] ==> 第一个参数 ,以此类推
    for key, cmd := range cmds {
        fmt.Println("key:", key, ", cmd:", cmd, ", cmds len:", len(cmds))
    }
​
    if len(cmds) < 2 {
        fmt.Println("请正确输入参数!")
        return
    }
​
    switch cmds[1] {
    case "hello":
        fmt.Println("hello")
        //go 的switch, 默认加上break了,不需要手动处理
        //如果想向下穿透的话,那么需要加上关键字: fallthrough
        fallthrough
    case "world":
        fmt.Println("world")
    default:
        fmt.Println("default called!")
    }
}

1586050055786.png

2. 标签

package main
​
import "fmt"func main() {
    //标签 LABEL1
    //goto LABEL  ===> 下次进入循环时,i不会保存之前的状态,重新从0开始计算,重新来过
    //continue LABEL1 ===> continue会跳到指定的位置,但是会记录之前的状态,i变成1
    //break LABEL1  ==> 直接跳出指定位置的循环//标签的名字是自定义的,后面加上冒号
LABEL121:
    for i := 0; i < 5; i++ {
        for j := 0; j < 5; j++ {
            if j == 3 {
                //goto LABEL1
                //continue LABEL1
                break LABEL121
                //break
            }
​
            fmt.Println("i:", i, ",j:", j)
        }
    }
​
    fmt.Println("over!")
}
​

1586050926287.png

3. 枚举const+iota

package main
​
import "fmt"//在go语言中没有枚举类型,但是我们可以使用const + iota(常量累加器)来进行模拟
//模拟一个一周的枚举
const (
    MONDAY    = iota       //0
    TUESDAY   = iota       //1
    WEDNESDAY = iota       //2
    THURSDAY               //3  ==> 没有赋值,默认与上一行相同iota ==> 3
    FRIDAY                 //4
    SATURDAY               //5
    SUNDAY                 //6
    M, N      = iota, iota //const属于预编译期赋值,所以不需要:=进行自动推导
)
​
const (
    JANU = iota + 1 //1
    FER             //2
    MAR             //3
    APRI            //4
)
​
//1. iota是常量组计数器
//2.iota从0开始,每换行递增1
//3. 常量组有个特点如果不赋值,默认与上一行表达式相同
//4.如果同一行出现两个iota,那么两个iota的值是相同的
//5.每个常量组的iota是独立的,如果遇到const iota会重新清零func main() {
​
    fmt.Println("打印周:")
    fmt.Println(MONDAY)
    fmt.Println(TUESDAY)
    fmt.Println(WEDNESDAY)
    fmt.Println(THURSDAY)
    fmt.Println(FRIDAY)
    fmt.Println("M:", M, ",N:", N)
​
    fmt.Println("打印月份:")
    fmt.Println(JANU) //1
    fmt.Println(FER)  //2
    fmt.Println(MAR)  //3//var number int
    //var name string
    //var flag bool
    //
    //
    ////可以使用变量组来将统一定义变量
    //var (
    //  number int
    //  name string
    //  flag bool
    //)
​
}
​

1586051900977.png

在goland中配置git shell,并且显示中文:

www.bbsmax.com/A/n2d9YvN6d…

我的安装路径D:\Program Files (x86)\Tools\Git\Git\etc)下bash.bashrc文件
​
export LANG="zh_CN.UTF-8"
export LC_ALL="zh_CN.UTF-8"

git终端显示中午设置:

1586052420518.png

4. 结构体

在go语言中,使用结构体来模拟类

package main
​
import "fmt"//c语言里面,我们可以使用typedef  int MyInt
type MyInt int //type相当于typdef//C:
//struct Person {
//
//}//go语言结构体使用type + struct来处理
type Student struct {
    name   string
    age    int
    gender string
    score  float64
}
​
func main() {
    t1 := struct {
        a int
    }{
        a : 100
    }
    
    fmt.Println(t1)
    
    var i, j MyInt
    i, j = 10, 20
​
    fmt.Println("i+j:", i+j)
​
    //创建变量,并赋值
    lily := Student{
        name:   "Lily",
        age:    20,
        gender: "女生",
        //score:  80, //最后一个元素后面必须加上逗号,如果不加逗号则必须与}同一行
        //}
        score: 80} //最后一个元素后面必须加上逗号,如果不加逗号则必须与}同一行//使用结构体各个字段
    fmt.Println("lily:", lily.name, lily.age, lily.gender, lily.score)
​
    //结构体没有-> 操作
    s1 := &lily
    fmt.Println("lily 使用指针s1.name打印:", s1.name, s1.age, s1.gender, s1.score)
    fmt.Println("lily 使用指针(*s1).name打印:", (*s1).name, s1.age, s1.gender, s1.score)
​
    //在定义期间对结构体赋值时,如果每个字段都赋值了,那么字段的名字可以省略不写
    //如果只对局部变量赋值,那么必须明确指定变量名字
    Duke := Student{
        name: "Duke",
        age:  28,
        //"男生",
        // 99,
    }
    Duke.gender = "男生"
    Duke.score = 100
​
    fmt.Println("Duke:", Duke)
}
​

1586053683685.png

5.init函数

C语言没有init函数,C语言一般需要自己去写init,然后在构造函数中调用

Go语言自带init函数,每一个包都可以包含一个或多个init函数

package sub
​
import "fmt"//0.这个init会在包被引用的时候(import)进行自动调用
//1.init函数没有参数,没有返回值,原型固定如下
//2.一个包中包含多个init时,调用顺序是不确定的(同一个包的多个文件中都可以有init)
//3. init函数时不允许用户显示调用的
//4. 有的时候引用一个包,可能只想使用这个包里面的init函数(mysql的init对驱动进行初始化)
//但是不想使用这个包里面的其他函数,为了防止编译器报错,可以使用_形式来处理
//import _ "xxx/xx/sub"
func init() {
    fmt.Println("this is first init() in package sub ==> sub.go")
}
​
func init() {
    fmt.Println("this is second init() in package sub ==> sub.go ")
}
​
//在go语言中,同一层级目录,不允许出现多个包名
func Sub(a, b int) int {
    //init() ==> 不允许显示调用
    test4() //由于test4与sub.go在同一个包下面,所以可以使用,并且不需要sub.形式
    return a - b
}
​

utils.go

package sub
​
//package utils //不允许出现多个包名import "fmt"func init() {
    fmt.Println("this is init in sub utils.go")
}
​
func test4() {
    fmt.Println("this is test4() in sub/utils!")
}
​

main.go

package main
​
import (
    _ "day02/05-init函数/sub" //此时,只会调用sub里面的init函数,编译还不会出错
    //"fmt"
)
​
func main() {
    //res := sub.Sub(10, 5)
    //fmt.Println("sub.Sub(20,10) =", res)
}
​

效果:

1586054701758.png

使用init场景,在配置文件管理器中写init,用于加载配置文件并解析:

configManager {
    //解析加载配置文件
    //IP, PORT
}

1586055043410.png

6.defer(延迟)

延迟,关键字,可以用于修饰语句,函数,确保这条语句可以在当前栈退出的时候执行

lock.Lock()
a = "hello"
lock.Unlock()   <=== 经常容易忘掉解锁

go语言可以使用defer来解决这个问题

{
    lock.Lock()
    defer lock.Unlock()   <=== 在当前栈退出的时候(例如:函数结束时)
    a = "hello"
}
​
{
    f1,_ := file.Open()
    defer f1.Close()
}

实例:

package main
​
import (
    "fmt"
    "os"
)
​
func main() {
    //1.延迟,关键字,可以用于修饰语句,函数,确保这条语句可以在当前栈退出的时候执行
    //2. 一般用于做资源清理工作
    //3. 解锁、关闭文件
    //4. 在同一个函数中多次调用defer,执行时类似于栈的机制:先后入后出
​
    filename := "01-switch.go"
    readFile(filename)
}
​
func readFile(filename string) {
    //func Open(name string) (*File, error) {
    //1. go语言一般会将错误码作为最后一个参数返回
    //2. err一般nil代表没有错误,执行成功,非nil表示执行失败
    f1, err := os.Open(filename)
​
    //匿名函数,没有名字,属于一次性的逻辑 ==> lamada表达式
    defer func(a int) {
        fmt.Println("准备关闭文件, code:", a)
        _ = f1.Close()
    }(100) //创建一个匿名函数,同时调用if err != nil {
        fmt.Println("os.Open("01-switch.go") ==> 打开文件失败, err:", err)
        return
    }
​
    defer fmt.Println("0000000")
    defer fmt.Println("1111111")
    defer fmt.Println("2222222")
​
    buf := make([]byte, 1024)  //byte ==> char ==> uint8
    //func (f *File) Read(b []byte) (n int, err error) {
    n, _ := f1.Read(buf)
    fmt.Println("读取文件的实际长度:", n)
    fmt.Println("读取的文件内容:", string(buf))  ==> 类型转换
​
}

1586056346132.png