美文网首页
go语法入门

go语法入门

作者: DayDayUpppppp | 来源:发表于2019-05-26 14:35 被阅读0次

利用周末的时间,简单的学习了一下go的语法。go的语言设计的基本理念是“简洁”。从关键字的设计上来说,也是非常的少,只有20多个。 语法上面虽然没有python简洁,但是总的来说,也是非常不错了。应该开发同样的逻辑,比c/c++的代码量少非常多。

语法相对友好,上手比较快之外,go还保持了不错了的性能。goroutine的设计的理念非常非常的牛逼,学名叫做CSP Communicating Sequential Processes(顺序通信处理), 通过共享的方式来做线程之间数据的同步。

除此之外,godoc,严格的语法检查,比如未使用的变量会报错,交叉编译等机制。可以保证一个大型项目的代码更加易于维护,保证一个项目组的开发人员写的代码在可维护的水准之上。

go的基本语法
  • 数组
package main
import "fmt"

func main() {
    p := []int{2, 3, 5, 7, 11, 13}
    // 打印整个数组
    fmt.Println("p == ", p)

    // 切片
    fmt.Println("p[1:4] ==", p[1:4])

    // 省略下标代表从 0 开始
    fmt.Println("p[:3] ==", p[:3])
    fmt.Println("p[4:] ==", p[4:])

    // 使用make 创建数组
    b := make([]int, 0, 5)   // 长度len(b)=0, 容量cap(b)=5
    fmt.Println("b == ", b)
}
  • 指针
var p *int
i := 42
p = &i
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21         // 通过指针 p 设置 i

指针和结构体

package main
import "fmt"

// 结构体的定义
type Vertex struct {
    X int
    Y int
}

func main() {
    fmt.Println(Vertex{1, 2})
    
    // 定义结构体
    var v Vertex
    v = Vertex{1, 2}
    fmt.Println(v)

    // 定义指针
    var pv *Vertex
    pv = &v 
    fmt.Println(*pv)
}

如果是c语言切换过来的人,估计在这个地方会有一些困惑,为什么指针是通过 . 的方式来访问成员的,而不是通过 -> 的方式?!

type Square struct {
    side int32
}

func (sq *Square) Area() int32 {
    return sq.side * sq.side
}

func main {

    s1 := Square{200}     // 这个按照c的标准应该是值的引用
    s2 := &Square{300}   // 指针

     // 为什么可以都可以用这样的方式去访问变量和函数? !
    fmt.Println("side %d, area %d", s1.side, s1.Area())
    fmt.Println("side %d, area %d", s2.side, s2.Area())
}

查了一下原因:
在 Go 语言中这叫 选择器(selector)。无论变量是一个结构体类型还是一个结构体类型指针,都使用同样的 选择器符(selector-notation) 来引用结构体的字段:

type myStruct struct { i int }
var v myStruct    // v是结构体类型变量
var p *myStruct   // p是指向一个结构体类型变量的指针
v.i
p.i

虽然语法的表述是一样的,但是内部实现的方式是:



结构体的方法
go中结构体的方法的语法形式是:

package main

import "fmt"

type TwoInts struct {
    a int
    b int
}

func main() {
    two1 := new(TwoInts)
    two1.a = 12
    two1.b = 10

    fmt.Printf("The sum is: %d\n", two1.AddThem())
    fmt.Printf("Add them to the param: %d\n", two1.AddToParam(20))

    two2 := TwoInts{3, 4}
    fmt.Printf("The sum is: %d\n", two2.AddThem())
}

func (tn *TwoInts) AddThem() int {
    return tn.a + tn.b
}

func (tn *TwoInts) AddToParam(param int) int {
    return tn.a + tn.b + param
}

字典 map

package main

import "fmt"

func main() {

    // 创建一个字典可以使用内置函数make
    // "make(map[键类型]值类型)"
    m := make(map[string]int)

    // 使用经典的"name[key]=value"来为键设置值
    m["k1"] = 7
    m["k2"] = 13

    // 用Println输出字典,会输出所有的键值对
    fmt.Println("map:", m)

    // 获取一个键的值 "name[key]".
    v1 := m["k1"]
    fmt.Println("v1: ", v1)

    // 内置函数返回字典的元素个数
    fmt.Println("len:", len(m))

    // 内置函数delete从字典删除一个键对应的值
    delete(m, "k2")
    fmt.Println("map:", m)

    // 根据键来获取值有一个可选的返回值,这个返回值表示字典中是否
    // 存在该键,如果存在为true,返回对应值,否则为false,返回零值
    // 有的时候需要根据这个返回值来区分返回结果到底是存在的值还是零值
    // 比如字典不存在键x对应的整型值,返回零值就是0,但是恰好字典中有
    // 键y对应的值为0,这个时候需要那个可选返回值来判断是否零值。
    _, ok := m["k2"]
    fmt.Println("ok:", ok)

    // 你可以用 ":=" 同时定义和初始化一个字典
    n := map[string]int{"foo": 1, "bar": 2}
    fmt.Println("map:", n)
}

  • import 自定义的包
$ tree
.
├── foo
│   └── test.go
└── main.go

main.go

package main

import "fmt"
import "./foo"

func main() {
  bar.Abc()
  fmt.Print("This is main\n")
}

test.go

package bar

import "fmt"

func Abc() {
  fmt.Print("This is test print\n")
}
# 执行
go run main.go 

接口与反射

看了一下go的语法,感觉go接口的设计,有一点想c++的函数指针。 (上层的模块在init的时候,传递给底层的模块一个函数指针,底层模块调用的时候,根据注册的函数指针,调用不同的函数。)

channel
默认的channel是阻塞式的,如果读取一个没有数据的channel的数据,它将会被阻塞;如果向channel发送数据,它将会被阻塞,直到数据被读出来。

package main

import "fmt"
import "time"

func test_func(a int, c chan int){
    c <- a                        // 写入数据,阻塞
    fmt.Println("test_func 1 ")
    
    c <- a*2                      // 再次写入数据,又阻塞
    fmt.Println("test_func 2 ")

    fmt.Println("end")
}

func main() {
    fmt.Println("begin ~~")
    
    c := make(chan int)        
    go test_func(10, c)

    time.Sleep(3 * time.Second)    // sleep 3 second 

    fmt.Println("begin ~~~~~ ")
    x := <- c                      // 读数据,channel那端的写入操作才会继续往下执行
    fmt.Println("end : ", x)

    // main 函数结束,程序结束
}

有缓存的channel

ch := make(chan type, value)

value指定了channel里面的元素的数量。比如value=5,那么前五个元素的写入是不会阻塞的。但是,第六个元素的写入会阻塞。

  • 错误处理
  • gorouting

gorouting的协程机制,可以非常简单的实现一个 “限频器”。比如,一个消息消费的接口的qps是1000。为了保护它不超过限制,写一个简单的例子:

    tick := time.Tick(1 * time.Second)

    for {
        <-tick
        fmt.Println("tick")
        // dosomething, proc msg , tick一秒被唤醒一次,也就是一秒处理一条消息;
    }

time.Tick() 是golang内置的一个接口,简单的原理是利用timer向chan里面周期性的写入一个消息。然后,消费消息的chan会阻塞在chan的另外一端阻塞读消息。这里可以先挖个坑,golang 的源码里面的timer模块可以拿出来讲一下。


参考 :

  1. https://www.kancloud.cn/kancloud/the-way-to-go

相关文章

  • Go 语法基础--学习笔记

    安装以及基本语法参考官方文档即可。 入门资源分享: Go 编程基础::无闻录制的新手入门视频教程 Go入门指南 :...

  • go语言常用资料整理

    go语言常用资料整理 入门 coolshell关于go的快速介绍 语法:https://coolshell.cn/...

  • go语法入门

    利用周末的时间,简单的学习了一下go的语法。go的语言设计的基本理念是“简洁”。从关键字的设计上来说,也是非常的少...

  • Go语言超详细学习知识体系

    Go编程入门 基础语法 环境安装 下载地址https://golang.google.cn/dl/ GOPATH、...

  • go语法快速入门

    第一个程序HelloWorld 按照国际惯例,我们来实现helloworld package main标注程序位置...

  • go语言十分钟入门教程

    [图片上传失败...(image-8dd502-1614683331867)] 导语|这是一篇go基本语法快速入门...

  • Go语言基础知识(一)

    Go 语言学习的入门部分,如果有C语言的基础类比学习会非常迅速。总结来说 Go语言 和 C语言很相似,语法更为简单...

  • golang读书笔记(一)

    其实《go in action》是一本不错的go入门书,但是由于在这本书的最开始不讲基本的语法,搞得本人在第二章直...

  • golang基础教程-快速入门go语言【含视频】

    此教程主要对go语言做了基本的语法和使用介绍,希望可以让想入门的小伙伴可以快速的学习go语言。 教程仅有不到2个小...

  • beego 模版语法

    beego 模板语法指南 本文讲述 beego 中使用的模板语法,与 go 模板语法基本相同。 基本语法 go 统...

网友评论

      本文标题:go语法入门

      本文链接:https://www.haomeiwen.com/subject/cxwxtctx.html