• 周日. 6 月 16th, 2024

    Go语言基础

    root

    10 月 13, 2019 #Golang
    源码文件使用UTF-8编码,对Unicode支持良好。
    每个源文件都属于包的一部分,在文件头部用package声明所属的包名称
    package man
    
    func man() {
        println("hello, world!")
    }
    
    以”.go”作为文件扩展名,语句结束分号默认省略,支持C样式注释
    入口函数main没有参数,必须放在main包中
    用import导入标准库或第三方包
    import "fmt"  //请删除未使用的导入,否则编译器会将其当作错误
    

    1. 变量

    使用var定义变量,支持类型推断。 基础数据类型划分清晰明确, 有助于编写跨平台应用。编译器确保变量总是被初始化为零值。
    在函数内部,可省略var关键字,使用更简单的定义模式
    package main
    
    func main() {
        x := 100
        println(x)
    }
    

    2. 表达式

    Go仅有三种流控制语句。
    // if
    func main() {
        x := 100
        if x > 0 {
            println("x")
        } else if x < 0 {
            println("-x")
        } else {
            println("0")
        }
    }
    
    //switch
    func main() {
        x := 100
        switch{
            case x > 0:
                println("x")
            case x < 0:
                println("-x")
            default:
                println("0")
        }
    }
    
    #for
    func main() {
        for i := 0; i<5; i++ {
            println(i)
        }
        for i:=4;i>=0; i-- {
            println(i)
        }
    }
    func main() {
        x := []int{100, 101, 102}
        //for...range 除元素外,还可返回索引
        for k, v := range x {
            println(x, ":", v)
        }
    }
    

    3 函数

    package main
    
    import (
        "errors"
        "fmt"
    )
    
    //函数可以定义多个返回值,甚至对其命名
    func div(a, b int) (int, error) {
        if b == 0 {
            return 0, errors.New("division by zero")
        }
        return a/b, nil
    }
    func main() {
        a, b := 10, 2   //定义多个变量
        c, err := div(a, b) //接收多返回值
        fmt.Println(c, err)
    }
    
    函数是第一类型,可以作为参数或返回值
    func test(x int) func() {   //返回函数类型
        return func() {         //匿名函数
            println(x)          //闭包
        }
    }
    func main() {
        x := 100
        f := test(x)
        f()
    }
    
    用defer定义延迟调用,无论函数是否出错,它都确保结束前被调用
    package main
    
    func test(a, b int) {
        defer println("dispose...") //常用来释放资源,解除锁定,或执行一些清理操作
                                    //可定义多个defer, 按FILO顺序执行
        println(a /b)
    }
    func main() {
        test(10, 0)
    }
    

    4. 数据

    切片(slice)可实现类似动态数组的功能
    package main
    
    import "fmt"
    
    func main() {
        x := make([]int, 0, 5) //创建容量为5的切片
        for i:=0;i<8;i++ {
            x = append(x, i)    //追加数据,当超出容量限制时,自动分配更大的存储空间
        }
        fmt.Println(x)
    }
    //输出
    //[0 1 2 3 4 5 6 7]
    
    将字典(map)类型内置,可直接从运行时层面获取性能优化.
    package main
    
    import "fmt"
    
    func main() {
        m := make(map[string]int)   //创建字典类型对象
        m["a"] = 1 //添加或设置
        x, ok := m["b"] //使用ok-idiom获取值,可知道key/value是否存在
        fmt.Println(x, ok)
        
        delete(m, "a")  //删除
    }
    /**
    所谓ok-idiom模式,是指在多返回值中用一个名为ok的布尔值来标示操作是否成功。因为很多操作默认返回零值,所以必须额外说明
    **/
    
    结构体(struct)可欺匿名嵌入其他类型
    package main
    
    import "fmt"
    
    type user struct {
        name string
        age byte
    }
    
    type manager struct {
        user                //匿名嵌入其他类型
        title string
    }
    
    func main() {
        var m manager
        
        m.name = "Tom"  //直接访问匿名字段的成员
        m.age = 29
        m.title = "CTO"
        
        fmt.Println(m)
    }
    /**
    输出:
    {{Tom 29} CTO}
    **/
    

    5. 方法

    可以为当前包内的任意类型定义方法
    package main
    
    type X int
    func (x *X) inc() { //名称前的参数称作receiver,作用类似python self
        *x++
    }
    func main() {
        var x X
        x.inc()
        println(x)
    }
    
    还可直接调用匿名字段的方法,这种方式可实现与继承类似的功能
    package main
    import "fmt"
    type user struct {
        name string
        age byte
    }
    
    func (u user)ToString() string {
        return fmt.Sprintf("%+v", u)
    }
    
    type manager struct {
        user
        title string
    }
    func main() {
        var m manager
        m.name = "Tom"
        m.age = 29
        println(m.ToString()) //调用user.ToString()
    }
    

    6. 接口

    接口采用了duck type方式,也就是说无须在实现类型上添加显式声明。
    package main
    import "fmt"
    type user struct {
        name string
        age byte
    }
    func (u user)Print() {
        fmt.Printf("%+v", u)
    }
    type Printer interface {    //接口类型
        Print()
    }
    func main() {
        var u user
        u.name = "Tom"
        u.age = 29
        var p Printer = u //只要包含接口所需的全部方法,即表示实现了该接口
        p.Print()
    }
    //另有空接口类型interface{}, 用途类似OOP里的system.Object, 可接收任意类型对象
    

    7 并发

    整个运行时完全并发化设置,几乎都在以goroutine方式运行。能轻松创建和运行成千上万的并发任务
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func task(id int) {
        for i:=0; i<5; i++ {
            fmt.Printf("%d: %d\n", id, i)
            time.Sleep(time.Second)
        }
    }
    func main() {
        go task(1)
        go task(2)
        time.Sleep(time.Second*6)
    }
    
    通道(channel)与goroutine搭配,实现用通信代替内存共享的CSP模型
    package main
    //消费者
    func consumer(data chan int, done chan bool) {
        for x:= range data { //接收数据,直到通道被关闭
            println("recv:", x)
        }
        done <- true    //通知main,消费结束
    }
    //生产者
    func producer(data chan int) {
        for i:=0;i<4;i++ {
            data <- i   //发送数据
        }
        close(data) //生产结束,关闭通道
    }
    func main() {
        done := make(chan bool) //用于接收消费结束信号
        data := make(chan int)  //数据管道
        
        go consumer(data, done) //启动消费者
        go producer(data)   //启动生产者
        
        <-done //阻塞,直到消费者发回结束信号
    }

    root

    发表回复