zoukankan      html  css  js  c++  java
  • go的语法

    概述

    有接触go语言,工作中用的比较少,偶尔做个小项目,最近看到的一个项目也从go迁移到java。

    但是对go还是恋恋不忘,它语法比较简洁,库也比较多,编译速度快,等等优点,让我忘不了。

    对go的语法做个简单的总结,内容主要来源官网的pdf,学习go语言

    语法

    安装和运行

    安装go,上官网学学,我的系统是mac 直接brew安装

    通过go build编译成二进制,然后直接运行,go提供了众多工具,说来惭愧用的比较少,build,test用的比较多吧

    至于包管理以前用govender,现在有官方的mod

    基础语法

    支持各种类型:bool,int,float,double,complex,int32,byte,int64,string

    注意go里面int和int32不是同一种类型,赋值需要转一次

    go的变量定义比较奇怪,据说是方便编译器解析比如,定义一个变量

      var a int = 12或者是自动推导  a:=12

    可以通过const xxx = aaa 定义常量

    可以使用iota定义枚举,它会自增

    也提供了丰富的string操作,这个是利器,其实程序员很大一部分工作都是在和字符串搏斗。

    控制结构和python很像,又不同,没有while,都通过for提供能够,也支持goto和switch

    switch里面不必要写break了,可以通过fallthrough进入下一个判断

    语法的例子

    var a int
    var b bool
    a = 1
    b = true
    fmt.Println(a, b)

    //多个变量赋值和丢弃
    a,b = 2,true
    a,_ = 12,false

    fmt.Println(const1, const2)

    //string
    str1 := "hi world!"
    csts := []rune(str1)
    csts[0] = 'a'
    str2 := string(csts)
    fmt.Printf("str2=%s ",str2)

    var comp complex64 = 5+5i;
    fmt.Printf("val %v ", comp)

    //var e error

    if a > 2{
    fmt.Printf("> a=%d ",a)
    }else{
    fmt.Printf("< a=%d ",a)
    }

    if err := os.Chmod("/data1/applogs",os.ModePerm); err != nil{

    fmt.Println(err)
    }else{
    fmt.Println("chmod ok!")
    }

    aFunc()

    for i:=0;i < 10;i++{
    fmt.Print(i)
    }

    //
    list1 := []string{"a","b","c","d"}
    for k,v := range list1{
    fmt.Print(k,":",v)
    }
    var c byte = 'e'
    switch {
    case '0' <=c:
    fmt.Println("aa")
    fallthrough
    case 'a' <= c:
    fmt.Println("bb")


    }


    i :=0 Here: fmt.Print(i) i++ if i < 10{ goto Here }else{ return }

    go提供了几种基础类型 数组,slice列表 map字典 chan

    除了chan用于管道通信,从效果上和其他语言没啥差别,语法有点不同,多用几次,熟练就好了

    slice和map的例子

    var arr1[10]int
        arr1[0] = 1
        fmt.Printf("%d",arr1[0])
    
        arr2 := [3]int{1,2,3}
        arr3 := [...]int{1,2,3}
        fmt.Println(arr2,arr3)
    
        arr4 := [3][2]int{{1,2},{3,4},{5,6}}
        fmt.Println(arr4)
    
    
        //slice
        slice1 := make([]int, 10)
        fmt.Println(len(slice1),cap(slice1))
        slice2 := arr2[1:2]
        slice2[0] = 123
        fmt.Println(arr2)
        slice2 = append(slice2,1,2,3,4,5,6)
        fmt.Println(slice2)
        slice3 := make([]int,20)
        n1:=copy(slice3,slice2)
        fmt.Println(n1,slice3)
    
        //map
        map1 := make(map[string]int)
        map1["a0"] = 123
        map1["a1"] = 123
        map1["a2"] = 123
        map1["a3"] = 123
        fmt.Println(map1)
        delete(map1,"a0")
        fmt.Println(map1)

    作用域的问题

      对于我这种新手来说go的作用域是最容易引起混乱的。因为参数可以随便传啊。一堆goroutine共享变量,很容易出错。

      注意全局变量和局部变量,也需注意 :=不仅仅是声明和创建, 

    函数

    go的函数支持几个特别的特性,多个返回值,函数做参数,命名返回,变参,panic,recover

    支持defer函数退出时执行,有点像try{}finally{}但是封装的更加方便,采用栈的方式去收集defer函数

    panic 有点像java的exception ,没有捕获一层层往上抛出。结合defer和recover我们可以用来处理特殊情况

    func testfunc(){
        //打印
        rec(1)
    
        //作用域
        p()
        fmt.Println(a1234)
        //多值返回
    
        //命名返回值
        ret1,ret2 := p12()
        fmt.Println(ret1, ret2)
    
        //延迟执行
        readWrite()
        //延迟的顺序
        deferSeq()
    
        //变参
        myFunc(1,2,3,4,5)
        //原样传递参数
        myFunc2(1,2,3,4,5)
        //函数作为值
        hello := func() {
            fmt.Println("hello world")
        }
        hello()
        //函数回调
        aCallback(10, func88)
        //使用panic
        bol := throwPanic(aPanic)
        fmt.Println("bol:",bol)
    
    
    }
    
    func throwPanic(f func())(b bool){
        defer func(){
            if x:=recover(); x!= nil{
                b = true
            }
        }()
        f()
        return false
    }
    
    func aPanic(){
        panic("throw a panic")
    }
    
    
    func aCallback(y int, f func(int)){
        f(y)
    }
    
    func func88(i int)  {
        fmt.Printf("i=%d",i*i)
    }
    
    
    func myFunc2(arg ...int){
        myFunc(arg...)
    }
    
    func myFunc(arg ...int)  {
        for _,n := range arg{
            fmt.Printf("n=%d,",n)
        }
    }
    
    
    
    func deferSeq()  {
        for i:=0; i < 5;i++{
            defer func(x int){
                fmt.Printf("%d	",x)
            }(i)
        }
    }
    
    func readWrite() bool{
        fp,err := os.Open("/data1/applogs/superfans/info-2019-01-02.log")
        defer fp.Close()
        if err != nil{
            return false
        }
    
        return true
    }
    
    
    
    func p12()(a int,b int){
        n := 1
        a = 1
        b = n
        return
    }
    
    
    var a1234 int
    
    func p(){
        a1234 := 5
        fmt.Println(a1234)
    }
    
    func rec(i int){
        if i == 10{
            return
        }
        rec(i+1)
        fmt.Printf("%d ", i)
    }

    go里面没有private protected publice关键字,通过大小写去区分公用还是私有,

    大写公用,小写属于包私有的

    内存分配

    make 只针对slice map chan,返回三种类型

    new 任意类型,分配内存空间,返回指针

    自定义类型

    和c一样,使用struct作为自定义类型

    go没有继承的概念,但是可以使用匿名字段

    也支持方法,但是必须在函数名字前面加上类型,其实是把类型也作为参数传递给函数吧

    go 有指针的概念,但是为了防止指针滥用,不支持指针的+和-

    这是上面说明的例子

    func testMoreFunc(){
        //指针
        var p *int
        fmt.Printf("%v",p)
        var i int
        p = &i
        fmt.Printf("%v",p)
        *p = 8
        fmt.Println("%v",i)
    
        //内存分配
        //new 返回地址 make返回自建类型
        psp := new (SynceBuffer)
        var syncbufer SynceBuffer
        fmt.Println("%v,%v",psp,&syncbufer)
        //仅仅适用于 map,slice,channel
        slice1:= make([]int, 10)
        map1 := make(map[string]string)
        chan1 := make(chan int,10)
        fmt.Println(len(slice1),len(map1),len(chan1))
    
        //直接使用符合声明创建
        syncbufer2 := &SynceBuffer{sync.Mutex{},bytes.Buffer{}}
        fmt.Println("%v",syncbufer2)
    
        //自定义类型
        testAge()
        //结构体字段
        aNull := struct{}{}
        fmt.Printf("%v", aNull)
    
        //大写不可导出,小写可以导出
        str1 := &Str1{name:"hehe"}
        str1.T12 = 12
        str1.showIt()
    
        //方法转换: 先找n, 再找&n
        str11 := Str1{name:"hehe11"}
        str11.showIt()
    
    
        //转换
        convertStr()
    
        //迁入的方式实现组合
    
    }
    
    func convertStr(){
        //byte类型转换
        mystr := "aba12"
        byteslice := []byte(mystr)
        runeSlice := []rune(mystr)
        fmt.Printf("%v, %v",byteslice, runeSlice)
        fmt.Printf("%v, %v",string(byteslice), string(runeSlice))
    
        //自定义类型的转换
        var t12 T12 = 123;
        var t13 int
        t13 = int(t12)
    
        fmt.Printf("%v", t13)
    
    
    }
    
    
    
    type T12 int
    type Str1 struct {
        T12
        name string
    }
    func (str1 *Str1) showIt(){
        fmt.Printf("%v", str1)
    }
    
    
    
    func testAge(){
        a := new(NameAge)
        a.name = "peter"
        a.age = 123
        fmt.Println("%v
    ",a)
    }
    
    type NameAge struct {
        name string
        age int
    }
    
    type SynceBuffer struct{
        lock sync.Mutex
        buffer bytes.Buffer
    }

    接口

    go的接口和python有点像,只要实现了某个方法你就可以实现转换

    支持类型判断  xx.(type) 

    也支持反射reflect,提供两类方法,一类是获取字段的type,一类是获取字段的value

    func testInterface(){
        //测试接口
        s1 := S1{1}
        //finter1(s1)//传递接口有问题,因为是*引用实现了接口
        finter1(&s1);
        //获取类型 .(type)
    
        //类型判断
        gtype(&s1)
    
        //方法的定义只能是本地的
    
        //接口名字,方法名+er
    
        //写代码时面向接口编程
    
        //自省和反射
        showTag(&Person{})
    
    
    
    }
    
    func showTag(i interface{}){
        t := reflect.TypeOf(i)
        v := reflect.ValueOf(i)
        fmt.Printf("%v,%v",t,v)
        switch t.Kind() {
        case reflect.Ptr:
            tag := t.Elem().Field(0).Tag
            fmt.Printf("tag:%s",tag)
        default:
            tag := t.Field(0).Tag
            fmt.Printf("tag:%s",tag)
        }
    }
    
    type Person struct {
        name string "namestr"
        age int
    }
    
    
    
    /*
    func (i int) assf(){
    
    }
    */
    
    func gtype(som interface{})int{
        return som.(I1).Get();
    }
    
    func finter1(i1 I1){
        switch t := i1.(type) {
        case *S1:
            fmt.Println("type is *s1")
        default:
            fmt.Println("%v",t)
        }
        fmt.Println(i1.Get())
        i1.Put(123)
        fmt.Println(i1.Get())
    }
    
    
    type I1 interface {
        Get()int
        Put(int)
    }
    
    type S1 struct {
        i int
    }
    func(p *S1) Get() int {
        return p.i;
    }
    func (p *S1)Put(v int){
        p.i = v
    }

    通道

    通道可以理解成管道,可以定义各种类型的通道,但是通道发送和接收必须成对出现,不然会报错

    可以定义任意类型的通道

    var a chan int ,  var b chan func(), var c chan struct{}

     通道没有if判断,却可以使用select做选择

    func tgoroutine(){
        //torungoroutine()
        torungoroutineChan()
    }
    
    func torungoroutineChan(){
        c := make(chan int,4)
        fmt.Println("i'm waitting")
    
        go readyNew("tom",1,c)
        go readyNew("tim",1,c)
    
        i := 0
        L:for{
            select{
             case <-c:
                 i++
                 if i > 1{
                     break L
                }
            }
        }
        close(c)
    
    }
    
    func readyNew(w string, sec int, c chan int ){
        time.Sleep(time.Duration(sec) * time.Second)
        fmt.Println(w," is ready")
        c <-1
    }
    
    
    func torungoroutine(){
        go ready("tom",2)
        go ready("ted",1)
        fmt.Println("i'm waitting")
        time.Sleep(5 * time.Second)
    }
    
    func ready(w string, sec int){
        time.Sleep(time.Duration(sec) * time.Second)
        fmt.Println(w," is ready")
    }

    常用的包

    参数获取,文件读取,命令行执行

    func netFunc(){
        r, err := http.Get("http://baidu.com")
        if err != nil{
            fmt.Printf("%v
    ", err)
            return
        }else{
            b, err := ioutil.ReadAll(r.Body)
            r.Body.Close()
            if err == nil{
                fmt.Printf("%s", string(b))
            }
        }
    }
    
    func cmdCommon(){
    
        cmd := exec.Command("/bin/ls","-l")
        buf,err := cmd.Output()
        if err != nil{
            fmt.Printf("err %v
    ",err)
        }else{
            fmt.Printf("buf:%s
    ",string(buf))
        }
    
    }
    
    func flagParse(){
        b := flag.Bool("b",false, "a bool")
        port := flag.String("port","33","set port")
        flag.Usage =func(){
            fmt.Fprintf(os.Stderr,"%s",os.Args[0])
            flag.PrintDefaults()
        }
        flag.Parse()
        fmt.Printf("%v,%v",*b,*port)
    }
    
    func dirOpt(){
        //文件操作
        fineName := "/data1test/"
        if f,e := os.Stat(fineName);e != nil{
            os.Mkdir(fineName,0755)
        }else{
            fmt.Printf("%v",f)
        }
    }
    
    func aBufOutput(){
        buf := make([]byte, 1024)
        f,_ := os.Open("/data1test/info-2019-01-02.log")
        defer f.Close()
        r := bufio.NewReader(f)
        w := bufio.NewWriter(os.Stdout)
        defer w.Flush()
        for{
            n,_ := r.Read(buf)
            if n == 0{
                break
            }
            os.Stdout.Write(buf[:n])
        }
    
    }
    
    func noBufOutput(){
        buf := make([]byte, 1024)
        f,_ := os.Open("/data1test/info-2019-01-02.log")
        defer f.Close()
        for{
            n,_ := f.Read(buf)
            if n == 0{
                break
            }
            os.Stdout.Write(buf[:n])
        }
    
    }

    总结

      go的语法告一段落,但是如果仅仅只了解这些还不足以写一个好的golang程序,但是调调库啥的是没问题。

      我们需要去读更多优秀的开源项目,汲取营养。

      后续我会说明一些好用的库,也会阅读一些项目的源码

  • 相关阅读:
    SqlMap入门
    本地文件上载到Docker容器
    CentOS7 安装Docker-ce
    windows10 子系统(WSL) 文件位置
    慕课网-安卓工程师初养成-5-1 编程练习
    慕课网-安卓工程师初养成-4-14 Java 循环语句之多重循环
    慕课网-安卓工程师初养成-4-13 练习题
    慕课网-安卓工程师初养成-4-12 Java循环跳转语句之 continue
    慕课网-安卓工程师初养成-4-11 Java循环跳转语句之 break
    慕课网-安卓工程师初养成-4-10 练习题
  • 原文地址:https://www.cnblogs.com/beckbi/p/10542318.html
Copyright © 2011-2022 走看看