美文网首页Golang学习
二. go的基础知识

二. go的基础知识

作者: 东方舵手 | 来源:发表于2018-07-12 17:52 被阅读0次
    1. 所有go源码以.go结尾

    2. 标识符以字母或下划线开头,大小写敏感,(_是特殊标识符,还可用来忽略结果)
      Go语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。大写字母和小写字母是不同的:heapSort和Heapsort是两个不同的名字。


      image.png
    3. GO有25个保留关键字


      image.png
    4. 此外,还有大约30多个预定义的名字,比如int和true等,主要对应内建的常量、类型和函数。

    内建常量: 
            true  false  iota  nil
    内建类型: 
            int    int8    int16    int32    int64
            uint   uint8   uint16   uint32   uint64    uintptr
            bool   byte    rune     string   error
            float32  float64  complex128  complex64
            
    内建函数: 
            make   len   cap   new   append   copy 
            real   imag  panic  close  delete  recover  complex 
    

    GO程序的一般结构

    1. Go程序是通过package来组织的,只有package名称为main的包可以包含main函数,一个可执行的程序,有且只有一个main包
    2. 任何一个代码文件隶属于一个包
    3. 通过import 关键字来导入其它非main包
      比如:import {
      "fmt"
      "os"
      }
    4. 同一个包中函数,直接调用
    5. 不同包中函数,通过包名+ . + 函数名调用
    6. 包访问权限规则:
      a. 函数名首字符大写即为 public
      b. 函数名首字符小写即为 private ,包外包不能访问

    GO的一些常用声明

    1. const :定义常量
      1.1 常量定义
        const Pi float64 = 3.14
        const zero = 0.0 // 浮点常量, 自动推导类型
    
        const ( // 常量组
            size int64 = 1024
            eof        = -1 // 整型常量, 自动推导类型
        )
        const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
        const a, b, c = 3, 4, "foo"
        // a = 3, b = 4, c = "foo"    //err, 常量不能修改
    

    1.2 枚举
    常量声明可以使用iota常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式

    在一个const声明语句中,在第一个声明的常量所在的行,iota将会被置为0,然后再每一个有常量声明的行加1 
        const (
            x = iota // x == 0
            y = iota // y == 1
            z = iota // z == 2
            w  // 这里隐式地说w = iota,因此w == 3。其实上面y和z可同样不用"= iota"
        )
    
        const v = iota // 每遇到一个const关键字,iota就会重置,此时v == 0
    
        const (
            h, i, j = iota, iota, iota //h=0,i=0,j=0 iota在同一行值相同
        )
    
        const (
            a       = iota //a=0
            b       = "B"
            c       = iota             //c=2
            d, e, f = iota, iota, iota //d=3,e=3,f=3
            g       = iota             //g = 4
        )
        
        const (
            x1 = iota * 10 // x1 == 0
            y1 = iota * 10 // y1 == 10
            z1 = iota * 10 // z1 == 20
        )
    
    
    1. var :全局变量的声明和赋值
      2.1 变量声明
      var v1 int
      var v2 int
      //一次定义多个变量
      var v3, v4 int 
      var (
          v5 int
          v6 int
      )
    
    

    2.2 变量初始化

        var v1 int = 10  // 方式1
        var v2 = 10       // 方式2,编译器自动推导出v2的类型
        v3 := 10           // 方式3,编译器自动推导出v3的类型
        fmt.Println("v3 type is ", reflect.TypeOf(v3)) //v3 type is  int
    
        //出现在 := 左侧的变量不应该是已经被声明过,:=定义时必须初始化
        var v4 int
        v4 := 2 //err
    

    2.3 匿名变量
    _(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃:

    _, i, _, j := 1, 2, 3, 4
    
    func test() (int, string) {
        return 250, "sb"
    }
    
    _, str := test()
    
    
    1. type :结构体和接口的声明
    2. func :声明函数
       func 函数名(参数列表)(返回值列表) {
           // 函数体
       }
      
      // 可变参数
      func add (arg... int){ // 0个或多个参数
      } 
      func add(a int,arg...int){// 1个或多个参数
      }
      func add(a int,b int,arg ...int){// 2个或多个参数
      }
      注意:其中arg 是一个slice,我们可以通过arg[index]一次访问所有参数,通过len(arg) 来判断传递参数的个数
      
    3. GO的代码注释
      /* 块注释 */
      // 行注释

    命令行运行程序

    image.png

    基础数据类型

    GO语言内置以下这些基础类型:

    类型 名称 长度 零值 说明
    bool 布尔类型 1 false 其值不为真即为假,不可以用数字代表true或false
    byte 字节型 1 0 uint8 别名
    rune 字符类型 4 0 专用于存储unicode编码,等价于uint32
    int,uint 整型 4或8 0 32位或64位
    int8,uint8 整型 1 0 -128~127 , 0 ~ 255
    int16,uint16 整型 2 0 -32768~32767, 0~65535
    int32,uint32 整型 4 0 -21亿 ~ 21亿 , 0 ~ 42亿
    int64,uint64 整型 8 0
    float32 浮点型 4 0.0 小数位精确到7位
    floate64 浮点型 8 0.0 小数位精确到15位
    complex64 复数类型 8
    complex128 复数类型 16
    uintptr 整型 4或8 足以存储指针的uint32或uint64整数
    string 字符串 "" utf-8 字符串
    slice 引用类型 nil
    map 引用类型 nil
    chan 引用类型 nil

    布尔类型

    var v1 bool
    v1 = true
    v2 := (1 == 2) // v2也会被推导为bool类型
    
    //布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换
    var b bool
    b = 1 // err, 编译错误
    b = bool(1) // err, 编译错误
    
    

    整型

        var v1 int32
        v1 = 123
        v2 := 64 // v1将会被自动推导为int类型
    
    

    浮点型

        var f1 float32
        f1 = 12
        f2 := 12.0 // 如果不加小数点, fvalue2会被推导为整型而不是浮点型,float64
    
    

    字符类型

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        var ch1, ch2, ch3 byte
        ch1 = 'a'  //字符赋值
        ch2 = 97   //字符的ascii码赋值
        ch3 = '\n' //转义字符
        fmt.Printf("ch1 = %c, ch2 = %c, %c", ch1, ch2, ch3)
    }
    
    

    字符串

        var str string                                    // 声明一个字符串变量
        str = "abc"                                       // 字符串赋值
        ch := str[0]                                      // 取字符串的第一个字符
        fmt.Printf("str = %s, len = %d\n", str, len(str)) //内置的函数len()来取字符串的长度
        fmt.Printf("str[0] = %c, ch = %c\n", str[0], ch)
    
        //`(反引号)括起的字符串为Raw字符串,即字符串在代码中的形式就是打印时的形式,它没有字符转义,换行也将原样输出。
        str2 := `hello
        mike \n \r测试
        `
        fmt.Println("str2 = ", str2)
        /*
            str2 =  hello
                  mike \n \r测试
        */
    
    

    复数类型

        var v1 complex64 // 由2个float32构成的复数类型
        v1 = 3.2 + 12i
        v2 := 3.2 + 12i        // v2是complex128类型
        v3 := complex(3.2, 12) // v3结果同v2
    
        fmt.Println(v1, v2, v3)
        //内置函数real(v1)获得该复数的实部
        //通过imag(v1)获得该复数的虚部
        fmt.Println(real(v1), imag(v1))
    
    

    包的格式化输出输入

    格式说明

    格式 含义
    %% 一个%字面
    %b 一个二进制整数值(基数为2),或者是一个(高级的)用科学计数法标识的指数为2的浮点数
    %c 字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
    %d 一个十进制数值(基数为10)
    %e 以科学记数法e 表示的浮点数或者复数值
    %E 以科学记数法E 表示的浮点数或者复数值
    %f 以标准记数法表示的浮点数或者复数值
    %g 以%e或者%f表示的浮点数或者复数,任何一个都以最为紧凑的方式输出
    %G 以%E或者%f 表示的浮点数或者复数,任何一个都以最为紧凑的方式输出
    %o 一个以八进制表示的数字(基数为8)
    %p 以十六进制(基数为16)表示的一个值的地址,前缀为0x,字母使用小写的a-f表示
    %q 使用Go语法以及必须时使用转义,以双引号括起来的字符串或者字节切片[]byte,或者是以单引号括起来的数字
    %s 字符串。输出字符串中的字符直至字符串中的空字符(字符串以'\0‘结尾,这个'\0'即空字符)
    %t 以true或者false输出的布尔值
    %T 使用Go语法输出的值的类型
    %U 一个用Unicode表示法表示的整型码点,默认值为4个数字字符
    %v 使用默认格式输出的内置或者自定义类型的值,或者是使用其类型的String()方式输出的自定义值,如果该方法存在的话
    %x 以十六进制表示的整型值(基数为十六),数字a-f使用小写表示
    %X 以十六进制表示的整型值(基数为十六),数字A-F使用小写表示

    输出

     //整型
        a := 15
        fmt.Printf("a = %b\n", a) //a = 1111
        fmt.Printf("%%\n")        //只输出一个%
    
        //字符
        ch := 'a'
        fmt.Printf("ch = %c, %c\n", ch, 97) //a, a
    
        //浮点型
        f := 3.14
        fmt.Printf("f = %f, %g\n", f, f) //f = 3.140000, 3.14
        fmt.Printf("f type = %T\n", f)   //f type = float64
    
        //复数类型
        v := complex(3.2, 12)
        fmt.Printf("v = %f, %g\n", v, v) //v = (3.200000+12.000000i), (3.2+12i)
        fmt.Printf("v type = %T\n", v)   //v type = complex128
    
        //布尔类型
        fmt.Printf("%t, %t\n", true, false) //true, false
    
        //字符串
        str := "hello go"
        fmt.Printf("str = %s\n", str) //str = hello go
    

    输入

        var v int
        fmt.Println("请输入一个整型:")
        fmt.Scanf("%d", &v)
        //fmt.Scan(&v)
        fmt.Println("v = ", v)
    

    类型转换

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

        var ch byte = 97
        //var a int = ch //err, cannot use ch (type byte) as type int in assignment
        var a int = int(ch)
    

    类型别名

        type bigint int64 //int64类型改名为bigint
        var x bigint = 100
    
        type (
            myint int    //int改名为myint
            mystr string //string改名为mystr
        )
    

    运算符

    算数运算符

    image.png

    关系运算符

    image.png

    逻辑运算符

    image.png

    位运算符

    image.png

    赋值运算符

    image.png

    其它运算符

    image.png

    运算符优先级
    在Go语言中,一元运算符拥有最高的优先级,二元运算符的运算方向均是从左至右。
    下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:

    image.png

    流程控制

    Go语言支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构。
     顺序结构:程序按顺序执行,不发生跳转。
     选择结构:依据是否满足条件,有选择的执行相应功能。
     循环结构:依据条件是否满足,循环多次执行某段代码。

    1. if语句
        var a int = 3
        if a == 3 { //条件表达式没有括号
            fmt.Println("a==3")
        }
    
        //支持一个初始化表达式, 初始化字句和条件表达式直接需要用分号分隔
        if b := 3; b == 3 {
            fmt.Println("b==3")
        }
    

    1.1 if...else 语句

        if a := 3; a == 4 {
            fmt.Println("a==4")
        } else { //左大括号必须和条件语句或else在同一行
            fmt.Println("a!=4")
        }
    

    1.2 if... else if ... else 语句

        if a := 3; a > 3 {
            fmt.Println("a>3")
        } else if a < 3 {
            fmt.Println("a<3")
        } else if a == 3 {
            fmt.Println("a==3")
        } else {
            fmt.Println("error")
        }
    
    1. switch 语句
      Go里面switch默认相当于每个case最后带有break,匹配成功后不会自动向下执行其他case,而是跳出整个switch, 但是可以使用fallthrough强制执行后面的case代码:
        var score int = 90
    
        switch score {
        case 90:
            fmt.Println("优秀")
            //fallthrough
        case 80:
            fmt.Println("良好")
            //fallthrough
        case 50, 60, 70:
            fmt.Println("一般")
            //fallthrough
        default:
            fmt.Println("差")
        }
    

    可以使用任何类型或表达式作为条件语句:

    //1
        switch s1 := 90; s1 { //初始化语句;条件
        case 90:
            fmt.Println("优秀")
        case 80:
            fmt.Println("良好")
        default:
            fmt.Println("一般")
        }
    
        //2
        var s2 int = 90
        switch { //这里没有写条件
        case s2 >= 90: //这里写判断语句
            fmt.Println("优秀")
        case s2 >= 80:
            fmt.Println("良好")
        default:
            fmt.Println("一般")
        }
    
        //3
        switch s3 := 90; { //只有初始化语句,没有条件
        case s3 >= 90: //这里写判断语句
            fmt.Println("优秀")
        case s3 >= 80:
            fmt.Println("良好")
        default:
            fmt.Println("一般")
        }
    
    1. 循环语句
      for语句
        var i, sum int
    
        for i = 1; i <= 100; i++ {
            sum += i
        }
        fmt.Println("sum = ", sum)
    

    range 语句

    关键字 range 会返回两个值,第一个返回值是元素的数组下标,第二个返回值是元素的值:
        s := "abc"
        for i := range s { //支持 string/array/slice/map。
            fmt.Printf("%c\n", s[i])
        }
    
        for _, c := range s { // 忽略 index
            fmt.Printf("%c\n", c)
        }
    
        for i, c := range s {
            fmt.Printf("%d, %c\n", i, c)
        }
    
    1. 跳转语句
      break 和 continue
    在循环里面有两个关键操作break和continue,break操作是跳出当前循环,continue是跳过本次循环。
        for i := 0; i < 5; i++ {
            if 2 == i {
                //break    //break操作是跳出当前循环
                continue //continue是跳过本次循环
            }
            fmt.Println(i)
        }
    
    注意:break可⽤于for、switch、select,⽽continue仅能⽤于for循环。
    

    goto

    用goto跳转到必须在当前函数内定义的标签:
    func main() {
        for i := 0; i < 5; i++ {
            for {
                fmt.Println(i)
                goto LABEL //跳转到标签LABEL,从标签处,执行代码
            }
        }
    
        fmt.Println("this is test")
    
    LABEL:
        fmt.Println("it is over")
    }
    

    函数

    image.png image.png

    无参无返回值

    func Test() { //无参无返回值函数定义
        fmt.Println("this is a test func")
    }
    
    func main() {
        Test() //无参无返回值函数调用
    }
    

    有参无返回值

    普通参数列表

    func Test01(v1 int, v2 int) { //方式1
        fmt.Printf("v1 = %d, v2 = %d\n", v1, v2)
    }
    
    func Test02(v1, v2 int) { //方式2, v1, v2都是int类型
        fmt.Printf("v1 = %d, v2 = %d\n", v1, v2)
    }
    
    func main() {
        Test01(10, 20) //函数调用
        Test02(11, 22) //函数调用
    }
    

    不定参数类型

    不定参数是指函数传入的参数个数为不定数量。为了做到这点,首先需要将函数定义为接受不定参数类型:

    //形如...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数
    func Test(args ...int) {
        for _, n := range args { //遍历参数列表
            fmt.Println(n)
        }
    }
    
    func main() {
        //函数调用,可传0到多个参数
        Test()
        Test(1)
        Test(1, 2, 3, 4)
    }
    

    不定参数的传递

    func MyFunc01(args ...int) {
        fmt.Println("MyFunc01")
        for _, n := range args { //遍历参数列表
            fmt.Println(n)
        }
    }
    
    func MyFunc02(args ...int) {
        fmt.Println("MyFunc02")
        for _, n := range args { //遍历参数列表
            fmt.Println(n)
        }
    }
    
    func Test(args ...int) {
        MyFunc01(args...)     //按原样传递, Test()的参数原封不动传递给MyFunc01
        MyFunc02(args[1:]...) //Test()参数列表中,第1个参数及以后的参数传递给MyFunc02
    }
    
    func main() {
        Test(1, 2, 3) //函数调用
    }
    

    无参有返回值

    有返回值的函数,必须有明确的终止语句,否则会引发编译错误。
    一个返回值

    func Test01() int { //方式1
        return 250
    }
    
    //官方建议:最好命名返回值,因为不命名返回值,虽然使得代码更加简洁了,但是会造成生成的文档可读性差
    func Test02() (value int) { //方式2, 给返回值命名
    value = 250
        return value
    }
    
    func Test03() (value int) { //方式3, 给返回值命名
        value = 250
        return
    }
    
    func main() {
        v1 := Test01() //函数调用
        v2 := Test02() //函数调用
        v3 := Test03() //函数调用
        fmt.Printf("v1 = %d, v2 = %d, v3 = %d\n", v1, v2, v3)
    }
    

    多个返回值

    func Test01() (int, string) { //方式1
        return 250, "sb"
    }
    
    func Test02() (a int, str string) { //方式2, 给返回值命名
        a = 250
        str = "sb"
        return
    }
    
    func main() {
        v1, v2 := Test01() //函数调用
        _, v3 := Test02()  //函数调用, 第一个返回值丢弃
        v4, _ := Test02()  //函数调用, 第二个返回值丢弃
        fmt.Printf("v1 = %d, v2 = %s, v3 = %s, v4 = %d\n", v1, v2, v3, v4)
    }
    

    有参有返回值

    //求2个数的最小值和最大值
    func MinAndMax(num1 int, num2 int) (min int, max int) {
        if num1 > num2 { //如果num1 大于 num2
            min = num2
            max = num1
        } else {
            max = num2
            min = num1
        }
    
        return
    }
    
    func main() {
        min, max := MinAndMax(33, 22)
        fmt.Printf("min = %d, max = %d\n", min, max) //min = 22, max = 33
    }
    

    递归函数

    递归指函数可以直接或间接的调用自身。
    递归函数通常有相同的结构:一个跳出条件和一个递归体。所谓跳出条件就是根据传入的参数判断是否需要停止递归,而递归体则是函数自身所做的一些处理。

    //通过循环实现1+2+3……+100
    func Test01() int {
        i := 1
        sum := 0
        for i = 1; i <= 100; i++ {
            sum += i
        }
    
        return sum
    }
    
    //通过递归实现1+2+3……+100
    func Test02(num int) int {
        if num == 1 {
            return 1
        }
    
        return num + Test02(num-1) //函数调用本身
    }
    
    //通过递归实现1+2+3……+100
    func Test03(num int) int {
        if num == 100 {
            return 100
        }
        return num + Test03(num+1) //函数调用本身
    }
    
    func main() {
    
        fmt.Println(Test01())    //5050
        fmt.Println(Test02(100)) //5050
        fmt.Println(Test03(1))   //5050
    }
    
    

    函数类型

    在Go语言中,函数也是一种数据类型,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。

    type FuncType func(int, int) int //声明一个函数类型, func后面没有函数名
    
    //函数中有一个参数类型为函数类型:f FuncType
    func Calc(a, b int, f FuncType) (result int) {
        result = f(a, b) //通过调用f()实现任务
        return
    }
    
    func Add(a, b int) int {
        return a + b
    }
    
    func Minus(a, b int) int {
        return a - b
    }
    
    func main() {
        //函数调用,第三个参数为函数名字,此函数的参数,返回值必须和FuncType类型一致
        result := Calc(1, 1, Add)
        fmt.Println(result) //2
    
        var f FuncType = Minus
        fmt.Println("result = ", f(10, 2)) //result =  8
    }
    

    匿名函数与闭包

    所谓闭包就是一个函数“捕获”了和它在同一作用域的其它常量和变量,这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量。

    相关文章

      网友评论

        本文标题:二. go的基础知识

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