• GO语言基础语法


    1. Go项目的目录结构

      一般的,一个Go项目在GOPATH下,会有如下三个目录:

      project

         --- bin

         --- pkg

         --- src

      其中,bin 存放编译后的可执行文件;pkg 存放编译后的包文件;src 存放项目源文件。一般,bin 和 pkg 目录可以不创建,go 命令会自动创建(如 go install),只需要创建 src 目录即可。对于 pkg 中的文件是 Go 编译生成的,而不是手动放进去的(一般文件后缀.a)对于 src 目录,存放源文件,Go 中源文件以包(package)的形式组织。通常,新建一个包就在src目录中新建一个文件夹。

    注意:GOPATH 允许多个目录存在和配置,当有多个目录时,请注意分隔符,多个 GOPATH 的时候 windows 是分号,linux 和 mac 系统时冒号,当有多个 GOPATH 时,默认会将 go get 的内容放在第一个目录下。

      在最终形成项目后(可能还会依赖github上的一些包)整体结构图如下所示:

      

    2. 行分隔符

      在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号( ; ) 结尾,因为这些工作都将由 Go 编译器自动完成。如果你打算将多个语句写在同一行,它们则必须使用分号( ; )人为区分,但在实际开发中我们并不鼓励这种做法。

    3. 注释

      注释不会被编译,每一个包应该有相关注释。

      单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾。如:

    1
    2
    3
    4
    5
    // 单行注释
    /*
         Author by liangyongxing
         我是多行注释
     */

    4. 内置关键字(25个都小写)

    break    default    const    interface    select    case    defer     go       map    struct    chan   
    goto     package    switch   fallthrouth   func    return  range    type    continue     import
    else     for    var

    5. Go程序的顺序结构

      要想写出让人看着赏心悦目的代码,且具有一定的企业标准规范,一般都是需要有一定的规范才能达到指定的要求,下面就来说说这个规范到底是什么?

      1. 第一行一定是通过 package 来组织的,是通过关键词 import 来引入所依赖的包(与 python 相类似)  ps: import "fmt"

      2. 注意:只有 package 名称为 main 的包才可以包含 main 函数

      3. 在引入包之后紧接着是通过 const 关键字来进行常量的定义          ps: const PI = 3.14

      4. 在函数体外部通过使用 var 关键字来进行全局变量的声明和赋值        ps: var name = "liang"

      5. 通过 type 关键字进行结构struct 或 接口interface 的声明          ps: type Manager struct {}  或  type formatter interface {}

      6. 通过 func 关键字来进行函数的声明                     ps: func main() {}

    按照以上顺序规范,编写的示例代码如下所示:

    复制代码
    // 当前程序的包名
    package main
    
    /**
     导入其他的包
     */
    import (
        std "fmt"
    )
    
    // 常量定义
    const PI = 3.14
    
    // 全局变量的声明和赋值
    var name = "liang"
    
    // 一般类型声明
    type newType int
    
    // 结构声明
    type Manager struct {
    }
    
    // 接口声明
    type formatter interface {
    }
    
    // 由 main 函数作为程序入口点启动
    func main() {
        std.Println("Hello World ! MyName is : " + name)
    }
    复制代码

     6. package 使用

    1. 正常引用

    1
    import "fmt"

     在此期间也可以使用别名,别名的主要作用就是当使用第三方包时,包名可能会非常接近或者相同,此时就可以使用别名来进行区别和调用,例如:

    import std "fmt"
    // 使用时可以通过别名直接调用
    std.Println("Hello World!")

    2. 批量引入

    import (
        std "fmt"
        "io"
        str "strings"      
    )

    这里可以引伸一下,既然导入多个包时可以进行简写,那么声明多个 常量、全局变量 或 一般类型(非接口、非结构)是否也可以用同样的方式呢?

    答案是肯定的,具体可见下面的案例:

    复制代码
    // 批量常量定义
    const (
        PI = 3.14
        CONSTA = "str"
        CONSTB = 1
        CONSTC = 2
    )
    
    // 批量全局变量的声明
    var (
        name = "liang"
        name1 = "abc"
        name2 = 3
    )
    
    // 批量一般类型声明
    type (
        newType int
        type_a float32
        type_b string
        type_c byte
    )
    复制代码

    3. 省略调用

    注意:

      1. 不建议使用,易混淆

      2. 不可以和别名同时使用

    复制代码
    import (
        . "fmt"
    )
    
    func main() {
        // 使用省略调用
        Println("Hello World!")  
    }
    复制代码

    4. _ 操作

      这个操作经常是让很多人费解的一个操作符,请看下面这个import

    import(
        "database/sql"
        _ "github.com/ziutek/mymysql/godrv"
    )

      _  操作符其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的 init 函数

    7. 可见性规则

      Go 语言中,使用 大小写 来决定该 常量、变量、类型、接口、接口 或 函数 是否可以被外部包所调用

      根据约定:

      1. 函数名 首字母 小写 即为 private

      2. 函数名 首字母 大写 即为 public

     8. Go基本类型

      1. 布尔型:bool

        -- 长度:1字节

        -- 取值范围:true/false

        -- 注意事项:不可以用数字代表 true 或 false

      2. 整型:int / uint

        -- 根据运行平台可能为 32 或 64 位

      3. 8位整型:int8 / uint8

        -- 长度:1字节

        -- 取值范围:-128~127 / 0~255

      4. 字节型:byte(是uint8别名)

        -- 长度:1字节

        -- 取值范围:0~255

      5. 16位整型:int16 / uint16

        -- 长度:2字节

        --取值范围:-32768~32767 / 0~65535

      6. 32位整型:int32(rune)/ unit32

        -- 长度:4字节

        -- 取值范围:-2^31~2^31-1 / 0~2^32-1

      7. 64位整型:int64 / uint64

        -- 长度:8字节

        -- 取值范围:-2^63~2^63-1 / 0~2^64-1

      8. 浮点型:float32 / float64

        -- 长度:4 / 8 字节

        -- 小数位:精确到 7/15 小数位

      9. 其他值类型

        -- array:数组类型

        -- struct:结构类型

        -- string:字符串类型

      10. 引用类型

        -- slice:切片类型

        -- map:哈希类型

        -- chan:管道类型

      11. 接口类型:interface

        函数类型:func

    9. 变量的声明与赋值

     1. 单个变量的声明与赋值

    复制代码
        var a int // 变量的声明
        a = 123 // 变量的赋值
    
        // 变量声明的同时赋值
        var b int = 321
    
        // 上行的格式可以省略变量类型,有系统推断
        var c = 321
        // 变量声明与赋值的最简写法
        d := 456
    复制代码

     2. 多个变量的声明与赋值

    复制代码
        var a, b, c, d int      // 多个变量的声明
        a, b, c, d = 1, 2, 3, 4 // 多个变量的赋值
    
        // 多个变量声明的同时赋值
        var e, f, g, h int = 5, 6, 7, 8
    
        // 省略变量类型,有系统推断
        var i, j, k, l = 9, 10, 11, 12
    
        // 多个变量声明与赋值的最简写法
        i, m, n, o := 13, 14, 15, 16
    复制代码

      _ (下划线) 是个特殊的变量名,任何赋予它的值都会被丢弃。在下面的例子中,我们将值 35 赋予 b,并同时丢弃 34:

    1
    _, b := 34, 35

     3. 字符串

      Go中的字符串都是采用UTF-8字符集编码。字符串是用一对双引号("")或反引号(` `)括 起来定义,它的类型是string。在Go中字符串是不可变的,例如下面的代码编译是会报错:

    1
    2
    var s string = "hello"
    s[0] = 'c'

       但如果真对想要修改怎么办呢?下面的代码可以实现:

    1
    2
    3
    4
    5
    s := "hello"
    c := []byte(s)    //将字符串 s 转换为 []byte 类型
    c[0] = 'c'
    s2 := string(c)   //再转换回 string 类型
    fmt.Printf("%s ", s2)

       Go 可以使用 + 操作符来连接两个字符串:

    1
    2
    3
    4
    s := "hello"
    m := " world"
    a := s + m
    fmt.Printf("%s ", a)

       修改字符串也可以写为:

    1
    2
    3
    s := "hello"
    s = "c" + s[1:]    //字符串虽然不能改,但可以进行切片操作
    fmt.Printf("%s ", s)

       如果想要声明一个多行的字符串怎么办呢?可以通过 `(反引号)来声明

    1
    2
    m := `hello
          world`

       ` 括起的字符串为 Raw 字符串,即字符串在代码中的形式就是打印时代形式,它没有字符转义,换行也将原样输出。

     4. 错误类型

      Go 内置有一个 error 类型,专门用来处理错误信息,Go 的package里面专门还有一个 errors 来处理错误

    1
    2
    3
    4
    err := errors.New("this is a error type, please check it.")
    if err != nil {
        fmt.Printf("%s ", err)
    }

     10. Go变量类型转换

      Go中不存在隐式转换,所有类型转换必须显式声明,且转换只能发生在两种相互兼容的类型之间

    复制代码
    // 在相互兼容的两种类型之间进行转换
    var a float32 = 1.1
    b := int(a)
    
    // 以下表达式无法通过编译
    var c bool = true
    d := int(c)
    复制代码

      那么,请看以下代码,看最终结果应该是什么?

    func main() {
        var a int = 65
        b := string(a)
        fmt.Println(b)  
    }

      运行结果位:A

      string() 表示将数据转换为文本格式,因为计算机中存储的任何内容本质上都是数字,因此此函数自然地认为我们需要的是数字65表示的文本为:A

      要想将数字转换为对应数字的字符串即:"65",则需要另外一个函数:strconv.Atoi(a) --> "65"

    11. 常量的定义与应用

    <1. 常量的定义

      1. 常量的值在编译时就已经确定

      2. 常量的定义格式与变量基本相同

      3. 等号右侧必须时常量或者常量表达式

      4. 常量表达式中的函数必须时内置函数

     示例如下:

    复制代码
    package main
    
    import std "fmt"
    
    // 定义单个常量
    const a int = 1
    const b = 'A'
    
    // 批量定义多个常量
    const (
        text = "123"
        length = len(text)
        num = b * 20
    )
    
    // 同时定义多个常量
    const i, j, k  = 1, "liang", 'B'
    
    func main() {
        std.Println(a, length, num, i, j, k)
    }
    复制代码

    以上代码运行结果如下所示:

    1
    1 3 1300 1 liang 66

     <2. 常量的初始化规则与枚举应用

      1. 在定义常量组时,如果不提供初始值,则表示将使用上行的表达式

      2. 使用相同的表达式不代表具有相同的值,例如下面介绍道道 iota

      3. iota 是常量的计数器,从 0 开始,组中每定义 1 个常量就会自动递增 1

      4. 通过初始化规则与 iota 可以达到枚举的效果

      5. 每遇到一个 const 关键字,iota 就会重置为 0

    具体详情请看下面代码示例:

    复制代码
    package main
    
    import std "fmt"
    
    // 批量定义多个常量
    const (
        a = "A"
        b        // a 与 b 都为 "A"
        c = iota
        d        // d 的值为 c+1
    )
    
    // 常量星期枚举应用
    const (
        // 第一个常量不可省略表达式
        _null = iota    // 为了将 0 值排除
        Monday
        Tuesday
        Wednesday
        Thursday
        Friday
        Saturday
        Sunday
    )
    
    func main() {
        std.Println(a, b, c, d)
        std.Println("星期列表:", Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)
    }
    复制代码

    以上代码运行结果如下所示:

    1
    2
    A A 2 3
    星期列表: 1 2 3 4 5 6 7

    让我们再看一个结合常量的 iota 与 << (位运算符) 实现计算机存储单位的枚举示例:

    复制代码
    package main
    
    import std "fmt"
    
    const (
        _        = iota
        KB float64 = 1 << (iota * 10)
        MB
        GB
        TB
        PB
        EB
        ZB
        YB
    )
    
    func main() {
        std.Println("KB:", KB)
        std.Println("MB:", MB)
        std.Println("GB:", GB)
        std.Println("TB:", TB)
        std.Println("PB:", PB)
        std.Println("EB:", EB)
        std.Println("ZB:", ZB)
        std.Println("YB:", YB)
    }
    复制代码

    运行以上代码打印结果如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    KB: 1024
    MB: 1.048576e+06
    GB: 1.073741824e+09
    TB: 1.099511627776e+12
    PB: 1.125899906842624e+15
    EB: 1.152921504606847e+18
    ZB: 1.1805916207174113e+21
    YB: 1.2089258196146292e+24

    12. 指针

      Go 虽然保留了指针,但与其他编程语言不同的是,在 Go 当中不支持指针运算以及 "->" 运算符,而直接采用 "." 选择符来操作指针目标对象的成员。

      1. 操作符 "&" 取变量地址,使用 "*" 通过指针间接访问目标对象

      2. 默认值为 nil 而非 NULL

      3. 在 Go 当中,++ 与 -- 是作为语句而并不是作为表达式的,这点很重要

    以上三点通过以下例子来说明:

    复制代码
    package main
    
    import (
        std "fmt"
    )
    
    func main() {
        a := 1
        //a := a++  // 这里是编译不过去的,因为 ++ 与 -- 是作为语句而并不是作为表达式
        a++        // 语句需要单独一行
    
        var p *int = &a
        std.Println(*p)
    }
    复制代码

    运行结果打印如下:

    1
    2

    申明:以上为Go语言最基础的一部分,下一节我会真对Go语言中的各种语句(if、for、switch等)进行说明。

  • 相关阅读:
    Kafka遇到30042ms has passed since batch creation plus linger time at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.valueOrError(FutureRecordMetadata.java:94)
    postgreSQL学习(二):pgsql的一些基础操作
    postgreSQL学习(一):在Linux下安装postgreSQL
    黑苹果 技嘉 B250M-DS3H-CF i57500 HD630 EFI引导驱动发布
    记录一次垃圾短信网站短链分析
    MYSQL timestamp NOT NULL插入NULL的报错问题
    Permissions 0755 for '/home/lonecloud/.ssh/id_rsa' are too open.
    工作笔记:/bin/bash^M: 坏的解释器: 没有那个文件或目录 问题解决
    nginx常用配置
    VMware配置centos虚拟机静态ip
  • 原文地址:https://www.cnblogs.com/grimm/p/7575952.html
Copyright © 2020-2023  润新知