云计算之go语言——基础语法(中)

雨燕双飞 提交于 2020-01-19 14:18:32
9 Go 语言循环语句
1, 概念
    在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。
2, 分类
    1. for 循环 :    重复执行语句块
        a. 语法:
            for init; condition; post {}
            for condition {}
            for {}
                init:  一般为赋值表达式,给控制变量赋初值;
                condition: 关系表达式或逻辑表达式,循环控制条件;
                post: 一般为赋值表达式,给控制变量增量或减量。
        b. 实例
            for02.go
                package main

                import "fmt"

                func main() {
                    sum := 0
                    for i := 0 ; i <= 10; i++ {
                        sum += i
                    }
                    fmt.Println(sum)
                }
            for03.go
                package main

                import "fmt"

                func main() {
                    sum :=1
                    for ; sum <=10 ; {
                        sum +=sum
                    }
                    fmt.Println(sum)
                    for sum <= 10 {
                        sum +=sum
                    }
                    fmt.Println(sum)
                }
        c. For-each range 循环
            这种格式的循环可以对字符串、数组、切片等进行迭代输出元素。
            实例:
                for04.go
                    package main
                    import "fmt"

                    func main() {
                        strings := []string{"google","runoob"}
                        for i,s :=range strings {
                            fmt.Println(i,s)
                        }

                        numbers := [6]int{1,2,3,5}
                        for i,x :=range numbers {
                            fmt.Printf("第%d位置X的值为 %d\n", i , x)
                        }

                        num2 :=[]int{11,22,33}
                        for i,x :=range num2 {
                            fmt.Printf("第%d位置X的值为 %d\n" , i , x)
                        }

                        str := "abcdefghijk"
                        for i,x :=range str {
                            fmt.Printf("第%d位置X的值为 %c\n" , i , x)
                        }
                    }


    2. 循环嵌套 :  在 for 循环中嵌套一个或多个 for 循环
        实例:
            for05.go
                package main
                import "fmt"

                func main() {
                    var i,j int
                    for i=2; i< 100 ; i++ {
                        for j=2;j<=(i/j);j++{
                            if(i%j==0){
                                break
                            }
                        }
                        if(j > (i/j)){
                            fmt.Printf("%d 是素数\n",i)
                        }
                    }
                }
            for06.go
                package main
                import "fmt"

                func main() {
                    for i :=1;i<=9;i++{
                        for j :=1;j<=i;j++{
                            fmt.Printf("%d x %d = %d \t",i,j,i*j)
                        }
                        fmt.Println()
                    }
                }

3, 循环控制语句
    1. 循环控制语句可以控制循环体内语句的执行过程。
    2. 分类
        break 语句:      经常用于中断当前 for 循环或跳出 switch 语句
            用途:
                a. 用户跳出当前循环,并开始执行循环之外的语句
                b. 在 switch 中跳出 case
                c. 在多重循环中,可以用标号 label 标出想要break的循环(label名称可以随便起)
            实例:
                for07.go
                    package main
                    import "fmt"

                    func main() {
                        num := 10
                        for ;num <= 20; num++ {
                            if num == 15 {
                                break
                            }
                            fmt.Println(num)
                        }
                    }
                for09.go
                    package main

                    import "fmt"

                    func main() {
                        // 不使用标记
                        fmt.Println("------break-----")
                        for i:=1;i<=3;i++{
                            fmt.Printf("i:%d\n",i)
                            for i2 := 11; i2 <= 13 ; i2 ++ {
                                fmt.Printf("i2:%d\n",i2)
                                break
                            }
                        }
                        // 使用标记
                        fmt.Println("------break label-----")
                        re:
                                for i := 1; i <= 3 ; i++ {
                                    fmt.Printf("i:%d\n",i)
                                    for i2 :=11 ; i2<=13;i2++ {
                                        fmt.Printf("i2:%d\n",i2)
                                        break re
                                    }
                                }
                    }

        continue 语句:    跳过当前循环的剩余语句,然后继续进行下一轮循环。
            实例
                for08.go
                    package main
                    import "fmt"

                    func main() {
                        num := 10
                        for ; num<=20 ; num++ {
                            if num == 15 {
                                continue
                            }
                            fmt.Println(num)
                        }
                    }
                for10.go
                    package main

                    import "fmt"

                    func main() {
                        // 不使用标记
                        fmt.Println("-------continue-------")
                        for i := 1;i<=3;i++{
                            fmt.Printf("i:%d\n",i)
                            for i2:=11;i2<=13;i2++{
                                fmt.Printf("i2:%d\n",i2)
                                continue
                            }
                        }
                        // 使用标记
                        fmt.Println("-------continue label-------")
                        re:
                            for i:=1;i<=3;i++{
                                fmt.Printf("i:%d\n",i)
                                for i2:=11;i2<=13;i2++{
                                    fmt.Printf("i2:%d\n",i2)
                                    continue re
                                }
                            }

                    }

        goto 语句:    将控制转移到被标记的语句。
            a. 说明:
                goto 语句可以无条件地转移到过程中指定的行。
                goto 语句通常与条件语句配合使用。可用来实现条件转移,构成循环,跳出循环体等功能。
                但是,在结构化程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。
            b. 实例:

4, 无限循环
    1. 如果循环中条件语句永远不为 false 则会进行无限循环,我们可以通过 for 循环语句中只设置一个条件表达式来执行无限循环
    2. 实例
        for01.go
            package main

            import "fmt"

            func main() {
                for true {
                    fmt.Printf("这是无限循环。\n")
                }
            }

10 Go 语言条件语句
1, 概念
    条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句。
2, 分类
    if 语句:         if 语句 由一个布尔表达式后紧跟一个或多个语句组成。
        实例:
            if01.go
                package main

                import "fmt"

                func main() {
                    a := 10
                    if a < 20 {
                        fmt.Printf("a 小于 20\n")
                    }
                    fmt.Printf("a 的值为 : %d\n", a)
                }

    if...else 语句:  if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。
        实例:
            if02.go
                package main

                import "fmt"

                func main() {
                    var a int = 10
                    if a < 20 {
                        fmt.Printf("a 小于 20\n")
                    } else {
                        fmt.Printf("a 大于 20\n")
                    }
                    fmt.Printf("a 的值为: %d\n",a)
                }

    if 嵌套语句:   你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。
        实例:
            if03.go
                package main

                import "fmt"

                func main() {
                    var a int=100
                    var b int=200
                    if a == 100 {
                        if b == 200 {
                            fmt.Printf("a 的值为:%d,b 的值为:%d\n",a,b)
                        }
                    }
                    fmt.Printf("a 的值为:%d\n",a)
                    fmt.Printf("b 的值为:%d\n",b)
                }
            if04.go
                package main

                import "fmt"

                func main() {
                    var a int
                    var b int
                    fmt.Printf("请输入密码:\n")
                    fmt.Scan(&a)
                    if a == 123 {
                        fmt.Printf("请再次输入密码:")
                        fmt.Scan(&b)
                        if b == 123 {
                            fmt.Printf("密码正确")
                        } else {
                            fmt.Printf("密码不正确")
                        }
                    }else{
                        fmt.Printf("密码不正确")
                    }
                }

    switch 语句: switch 语句用于基于不同条件执行不同动作。
        实例:
            switch01.go
                package main

                import "fmt"

                func main() {
                    var grade string = "B"
                    var marks int = 90

                    switch marks {
                    case 90: grade = "A"
                    case 80: grade = "B"
                    case 50,60,70: grade = "C"
                    default:
                        grade = "D"
                    }
                    switch {
                    case grade == "A":
                        fmt.Printf("优秀\n")
                    case grade == "B", grade == "C":
                        fmt.Printf("良好\n")
                    case grade == "D":
                        fmt.Printf("及格\n")
                    case grade == "F":
                        fmt.Printf("不及格\n")
                    default:
                        fmt.Printf("差\n")
                    }
                    fmt.Printf("你的等级是 %s \n", grade)
                }
        Type Switch
            switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。
                实例:
                    switch02.go
                        package main

                        import "fmt"

                        func main() {
                            var x interface{}

                            switch i := x.(type) {
                            case nil:
                                fmt.Printf(" x 的类型: %T", i)
                            case int:
                                fmt.Printf(" x 的类型:int")
                            case float64:
                                fmt.Printf("x 是 float64型")
                            case func(int) float64:
                                fmt.Printf("x 是 func(int) 类型")
                            case bool , string:
                                fmt.Printf("x 是 bool 或 string 类型")
                            }
                        }
        fallthrough: 使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。
            实例:
                switch03.go
                    package main

                    import "fmt"

                    func main() {
                        switch {
                        case false:
                            fmt.Println("1, case 条件为false")
                            fallthrough
                        case true:
                            fmt.Println("2, case 条件为true")
                            fallthrough
                        case false:
                            fmt.Println("3, case 条件为false")
                            fallthrough
                        case true:
                            fmt.Println("4, case 条件为true")
                        case false:
                            fmt.Println("5, case 条件为false")
                            fallthrough
                        default:
                            fmt.Println("6, 默认 case")
                        }
                    }
            从以上代码输出的结果可以看出:switch 从第一个判断表达式为 true 的 case 开始执行,如果 case 带有 fallthrough,程序会继续执行下一条 case,且它不会去判断下一个 case 的表达式是否为 true。
    select 语句: select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
        select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
        select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。
        语法描述:
            每个 case 都必须是一个通信
            所有 channel 表达式都会被求值
            所有被发送的表达式都会被求值
            如果任意某个通信可以进行,它就执行,其他被忽略
            如果有多个 case 都可以运行, Select 会随机公平地选出一个执行。其他不会执行。
            否则:
                1. 如果有 default 子句,则执行该语句。
                2. 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。
        实例:
            select01.go
                package main

                import "fmt"

                func main() {
                    var c1,c2,c3 chan int
                    var i1,i2 int
                    select {
                    case i1 = <-c1:
                        fmt.Printf("received ",i1, "from c1\n")
                    case c2 <- i2:
                        fmt.Printf("sent ", i2, " to c2\n")
                    case i3, ok :=(<-c3):
                        if ok{
                            fmt.Printf("received ", i3 , "from c3\n")
                        } else {
                            fmt.Printf("c3 is closed\n")
                        }
                    default:
                        fmt.Printf("no commuinication\n")
                    }
                }
        select 会循环检测条件,如果有满足则执行并退出,否则一直循环检测。
            select02.go
                package main

                import (
                    "fmt"
                    "time"
                )

                func Chann(ch chan int, stopCh chan bool){
                    var i int
                    i = 10
                    for j:=0;j<10;j++{
                        ch <- i
                        time.Sleep(time.Second)
                    }
                    stopCh <- true
                }

                func main() {
                    ch := make(chan int)
                    c :=0
                    stopCh := make(chan bool)

                    go Chann(ch, stopCh)

                    for {
                        select {
                        case c= <-ch:
                            fmt.Println("Receive",c)
                            fmt.Println("channel")
                        case s :=<-ch:
                            fmt.Println("Receive",s)
                        case _ = <-stopCh:
                            goto end
                        }
                    }
                    end:
                }

    注意:Go 没有三目运算符,所以不支持 ?: 形式的条件判断。
    备注:
        goroutine: Go语言程序的并发体,channels 是它们之间的通信机制。

11 Go 语言函数
1,描述
    函数是基本的代码块,用于执行一个任务。
    Go 语言最少有个 main() 函数。
    你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
    函数声明告诉了编译器函数的名称,返回类型,和参数。
    Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。
2,函数定义
    func function_name( [parameter list] ) [return_types] {
       函数体
    }
    func:函数由 func 开始声明
    function_name:函数名称,函数名和参数列表一起构成了函数签名。
    parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
    return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
    函数体:函数定义的代码集合。
3,实例
    func01.go
        package main

        import "fmt"

        func main() {
            var a int = 100
            var b int = 200
            var ret int
            ret = max(a,b)
            fmt.Printf("最大值是:%d\n", ret)
        }

        func max(num1 , num2 int ) int{
            var result int
            if(num1 > num2){
                result = num1
            } else {
                result = num2
            }
            return result
        }
    func02.go
        package main

        import "fmt"

        func swap(x,y string )(string,string){
            return y,x
        }

        func main() {
            a,b := swap("Google","Runoob")
            fmt.Println(a,b)
        }
4, 函数参数
    函数如果使用参数,该变量可成为函数的形参。
    形参就像定义在函数体内的局部变量。
    调用函数,可以通过两种方式来传递参数。
        值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
        引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
        默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
    实例:
        func03.go
            package main

            import "fmt"

            func main() {
                a := 100
                b := 200
                fmt.Printf("交换前 a 的值为: %d\n",a)
                fmt.Printf("交换前 b 的值为: %d\n",b)

                swap(a,b)

                fmt.Printf("交换后 a 的值为:%d\n",a)
                fmt.Printf("交换后 b 的值为:%d\n",b)
            }

            func swap(x,y int) int  {
                var tmp int

                tmp = x
                x = y
                y = tmp

                return tmp
            }
5, 函数用法
    函数作为另外一个函数的实参: 函数定义后可作为另外一个函数的实参数传入
        func05.go
            package main

            import (
                "fmt"
                "math"
            )

            func main(){
                getSquareRoot := func(x float64) float64 {
                    return math.Sqrt(x)
                }
                fmt.Println(getSquareRoot((9)))
            }

    闭包:    闭包是匿名函数,可在动态编程中使用
        func06.go
            package main

            import "fmt"

            func getSequence() func() int  {
                i := 0
                return func() int{
                    i++
                    return i
                }
            }

            func main()  {
                nextNumber := getSequence()
                fmt.Println(nextNumber())
                fmt.Println(nextNumber())
                fmt.Println(nextNumber())
                nextNumber1 := getSequence()
                fmt.Println(nextNumber1())
                fmt.Println(nextNumber1())
            }
        func07.go
            package main

            import "fmt"

            func main() {
                add_func := add(1,2)
                fmt.Println(add_func())
                fmt.Println(add_func())
                fmt.Println(add_func())
            }

            func add(x1,x2 int) func()(int,int)  {
                i := 0
                return func() (int,int){
                    i++
                    return i , x1+x2
                }
            }

        func08.go
            package main

            import "fmt"

            func main() {
                add_func := add(1,2)
                fmt.Println(add_func(1,1))
                fmt.Println(add_func(0,0))
                fmt.Println(add_func(2,2))
            }

            func add(x1,x2 int) func(x3 int, x4 int)(int,int,int){
                i := 0
                return func(x3 int, x4 int)(int,int,int){
                    i++
                    return i,x1+x2,x3+x4
                }
            }

    方法:    方法就是一个包含了接受者的函数
        func09.go
            package main

            import (
                "fmt"
            )

            /* 定义结构体 */

            type Circle struct {
                radius float64
            }

            func main() {
                var c1 Circle
                c1.radius = 10.00
                fmt.Println("圆的面积 = ", c1.getArea())
            }

            /* 该 method 属于 Circle 类型对象中的方法 */
            func (c Circle) getArea() float64 {
                // c.radius 即为 Circle 类型对象中的熟悉
                return 3.14 * c.radius * c.radius
            }
        注意: go语言没有面向对象开发,但是这个方法配合结构体和面向对象开发类似。

12 Go 语言变量作用域
1, 概念:
    作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。
    换句话说:就是这个标识符可以在哪里使用
2,声明:
    函数内定义的变量称为局部变量
        scope01.go
            package main

            import "fmt"

            func main() {
                var a,b,c int
                a = 10
                b = 20
                c = a + b
                fmt.Printf("结果: a = %d , b = %d , c = %d",a,b,c)
            }

    函数外定义的变量称为全局变量
        scope02.go
            package main

            import "fmt"

            var g int

            func main() {
                var a,b int
                a = 10
                b = 20
                g = a + b
                fmt.Printf("结果: a = %d , b = %d , g = %d", a,b,g)
            }

        Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。
    函数定义中的变量称为形式参数
        scope03.go
            package main

            import "fmt"

            var a int = 20 ;

            func main() {
                var a int = 10
                var b int = 20
                var c int = 0

                fmt.Printf("main()函数中 a= %d\n",a)
                c = sum(a,b)
                fmt.Printf("main()函数中 c=%d\n",c)
            }
            func sum(a,b int) int  {
                fmt.Printf("sum()函数中 a=%d\n",a)
                fmt.Printf("sum()函数中 b=%d\n",b)
                return  a + b
            }
3,初始化局部和全局变量
    不同类型的局部和全局变量默认值为:
        int         0
        float32     0
        pointer     nil

13 Go 语言数组
1,概念
    Go 语言提供了数组类型的数据结构。
    数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。
    数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。
2,声明数组
    Go 语言数组声明需要指定元素类型以及元素个数
        var variable_name [SIZE] variable_type
        例子
            var balance [10] float32
3,初始化数组
    实例
        var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
    初始化数组中 {} 中的元素个数不能大于 [] 中的数字。
    如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:
4,访问数组元素
    var salary float32 = balance[9]
    实例:
        list01.go
            package main

            import "fmt"

            func main() {
                var n [10] int
                var i,j int

                for i=0;i<10;i++{
                    n[i] = i + 100
                }
                for j = 0 ; j<10;j++{
                    fmt.Printf("Element[%d] = %d\n" , j , n[j])
                }

                var l  = [5]int{1,2,3,3,4,}
                for m := 0;m<5 ; m++{
                    fmt.Println(l[m])
                }
            }

5,更多内容
    多维数组   Go 语言支持多维数组,最简单的多维数组是二维数组
        a. 初始化二维数组
            a = [3][4]int{
                {0,1,2,3},
                {4,5,6,7},
                {8,9,10,11},
            }
            注意:以上代码中倒数第二行的 } 必须要有逗号,因为最后一行的 } 不能单独一行
            实例:
                list02.go
                    package main

                    import "fmt"

                    func main() {
                        var a=[5][2]int{
                            {0,0},
                            {1,2},
                            {2,4},
                            {3,6},
                            {4,8},
                        }
                        // {4,8}后面逗号不能去掉
                        for i:=0;i<5;i++{
                            for j:=0;j<2;j++{
                                fmt.Printf("a[%d][%d] = %d\n",i,j,a[i][j])
                            }
                        }
                    }

    向函数传递数组    你可以向函数传递数组参数
        如果你想向函数传递数组参数,你需要在函数定义时,声明形参为数组,我们可以通过以下两种方式来声明:
        方式一:
            void myFunction(param [10]int){}
        方式二:
            void myFunction(param []int){}
        实例:
            list03.go
                package main

                import "fmt"

                func main() {
                    var balance = [5]int{1000,2,3,17,50}
                    var avg float32
                    /* 数组作为参数传递给函数 */
                    avg = getAverage(balance,5)
                    /* 输出返回的平均值 */
                    fmt.Printf("平均值为:%f",avg)
                }
                func getAverage(arr [5]int, size int) float32  {
                    var i , sum int
                    var avg float32
                    for i=0;i<size;i++{
                        sum +=arr[i]
                    }
                    avg = float32(sum) / float32(size)
                    return avg
                }

14 Go 语言指针
1,概念
    Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。
    变量是一种使用方便的占位符,用于引用计算机内存地址。
    Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
    一个指针变量指向了一个值的内存地址。
    类似于变量和常量,在使用指针前你需要声明指针。
    var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明:
        var ip *int         /* 指向整型 */
        var fp *float32     /* 指向浮点型 */
2,内存地址实例
        pinter01.go
            package main

            import "fmt"

            func main() {
                var a int = 10
                fmt.Printf("变量的地址:%x\n" , &a)
            }
3,如何使用指针
    a. 指针使用流程
        定义指针变量
        为指针变量赋值
        访问指针变量中指向地址的值
    b. 实例
        pointer02.go
            package main

            import "fmt"

            func main() {
                var a int = 20 /* 声明实际变量 */
                var ip *int /* 声明指针变量 */
                ip = &a /* 指针变量的存储地址 */
                fmt.Printf("a 变量的地址是:%x\n",&a)

                /* 指针变量的存储地址 */
                fmt.Printf("ip 变量存储的指针地址:%x\n",ip)

                /* 使用指针访问值 */
                fmt.Printf("*ip 变量的值:%d\n", *ip)
                fmt.Printf("*&a 的值:%d\n",*&a)
            }
4,Go 空指针
    当一个指针被定义后没有分配到任何变量时,它的值为 nil。
    nil 指针也称为空指针。
    nil 在概念上和其它语言的null/None/nil/NULL一样,都指代零值或空值。
    一个指针变量通常缩写为 ptr 。
    实例:
        pointer03.go
            package main

            import "fmt"

            func main() {
                var ptr *int
                fmt.Printf("ptr 的值为: %x\n",ptr)
            }
    空指针判断:
        if(ptr != nil) /* ptr 不是空指针 */
        if(ptr == nil) /* ptr 是空指针 */
    指针更多内容
        Go 指针数组:            你可以定义一个指针数组来存储地址
            pointerlist01.go
                package main

                import "fmt"

                const MAX int = 3

                func main() {
                    a := []int{10,100,200}
                    var i int

                    for i=0;i<MAX;i++{
                        fmt.Printf("a[%d] = %d\n",i,a[i])
                    }
                }
            ptr 为整型指针数组。因此每个元素都指向了一个值。以下实例的三个整数将存储在指针数组中:
            pointerlist01.go
                package main

                import "fmt"

                const MAX int = 3

                func main() {
                    a := []int{10,100,200}
                    var i int
                    var ptr [MAX]*int

                    for i = 0;i<MAX;i++{
                        ptr[i] = &a[i] /* 整数地址赋值给指针数组 */
                    }

                    for i=0;i<MAX;i++{
                        fmt.Printf("a[%d] = %d\n",i,*ptr[i])
                    }
                }

        Go 指向指针的指针:      Go 支持指向指针的指针
            如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。
            当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址。
            指针变量声明格式:
                var ptr **int
            实例:
                pointerlist02.go
                    package main

                    import "fmt"

                    func main() {
                        var a int
                        var ptr *int
                        var pptr **int
                        a = 3000
                        ptr = &a
                        pptr = &ptr
                        fmt.Printf("变量 a = %d\n",a)
                        fmt.Printf("指针变量 *ptr = %d\n", *ptr)
                        fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
                    }

        Go 向函数传递指针参数:  通过引用或地址传参,在函数调用时可以改变其值
            Go 语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可。
            实例:向函数传递指针,并在函数调用后修改函数内的值
                pointerfunc01.go
                    package main

                    import "fmt"

                    func main() {
                        var a int = 100
                        var b int = 200
                        fmt.Printf("交换前 a 的值: %d \n", a)
                        fmt.Printf("交换前 b 的值: %d \n", b)
                        /* 调用函数用于交换值
                        * &a 指向 a 变量的地址
                        * &b 指向 b 变量的地址
                        */
                        swap(&a,&b)
                        fmt.Printf("交换后 a 的值: %d \n", a)
                        fmt.Printf("交换后 b 的值: %d \n", b)
                    }

                    func swap(x *int, y *int){
                        var tmp int
                        tmp = *x
                        *x = *y
                        *y = tmp
                    }

15 Go 语言结构体
1,概念
    Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
    结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
    结构体表示一项记录,比如保存图书馆的书籍记录。
2,定义结构体
    结构体定义需要使用 type 和 struct 语句。 struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。
    格式:
        type struct_variable_type struct {
            member definition
            member definition
            ...
            member definition
        }
    一旦定义了结构体类型,他就能用于变量的声明,语法格式如下:
        variable_name := structure_variable_type {value1,value2,...}
        variable_name := structure_variable_type {k1:v1,k2:v2,k3:v3}
    实例:
        struct01.go
            package main

            import "fmt"

            type Books struct {
                title string
                author string
                subject string
                book_id int
            }

            func main() {
                // 创建一个新的结构体
                fmt.Println(Books{"Go 语言","www.runoob.com","Go 语言教程", 1826262})
                // 也可以使用 k=>v格式
                fmt.Println(Books{title:"Go 语言",author:"www.runoob.com",subject:"Go 语言教程",book_id:1826262})
                // 忽略的字段为0或空
                fmt.Println(Books{title:"Go 语言",author:"www.runoob.com"})
            }
3,访问结构体成员
    如果要访问结构体成员,需要使用点号.操作符
        实例:
            struct02.go
                package main

                import "fmt"

                type Books struct {
                    title string
                    author string
                    subject string
                    book_id int
                }

                func main() {
                    var Book1 Books
                    var Book2 Books
                    Book1.title = "Go 语言"
                    Book1.author = "www.runoob.com"
                    Book1.subject = "Go 语言教程"
                    Book1.book_id = 1826262

                    Book2.title = "Python教程"
                    Book2.author = "www.runoob.com"
                    Book2.subject = "Python 语言教程"
                    Book2.book_id = 6262182
                    fmt.Printf("Book1 title: %s\n",Book1.title)
                    fmt.Printf("Book1 author: %s\n",Book1.author)
                    fmt.Printf("Book2 title: %s\n",Book2.title)
                    fmt.Printf("Book2 author: %s\n",Book2.author)
                }
4,结构体作为函数参数
    你可以像其他数据类型一样将结构体类型作为参数传递给函数。
    struct03.go
        package main

        import "fmt"

        type Books struct {
            title string
            author string
            subject string
            book_id int
        }

        func main() {
            var Book1 Books
            var Book2 Books
            Book1.title = "Go 语言"
            Book1.author = "www.runoob.com"
            Book1.subject = "Go 语言教程"
            Book1.book_id = 6495407

            /* book 2 描述 */
            Book2.title = "Python 教程"
            Book2.author = "www.runoob.com"
            Book2.subject = "Python 语言教程"
            Book2.book_id = 6495700

            /* 打印 Book1 信息 */
            printBook(Book1)

            /* 打印 Book2 信息 */
            printBook(Book2)
        }

        func printBook( book Books ) {
           fmt.Printf( "Book title : %s\n", book.title)
           fmt.Printf( "Book author : %s\n", book.author)
           fmt.Printf( "Book subject : %s\n", book.subject)
           fmt.Printf( "Book book_id : %d\n", book.book_id)
        }
    struct04.go
        package main

        import "fmt"

        type Student struct {
            name string
            age int
            classname string
            score int
        }

        func (s *Student) Totle() int {  // 为 Student 类型绑定 Totle的方法。*Student为指针引用,可以修改传入参数的值
            return s.score * 5  //方法归属于类型,不归属于具体的对象,声明该类型的对象即可调用该类型的方法
        }

        func main() {
            var stu1 Student
            var stu2 Student

            stu1.name = "张三"
            stu1.age = 24
            stu1.classname="初一"
            stu1.score = 89

            stu2.name = "李四"
            stu2.age = 20
            stu2.classname = "初二"
            stu2.score = 95
            fmt.Printf(stu1.name,stu1.age,stu1.classname,stu1.score,stu1.Totle())
            fmt.Printf(stu2.name,stu2.age,stu2.classname,stu2.score,stu2.Totle())
        }

16 Go 语言切片
1, 概念
    Go 语言切片是对数组的抽象。
    Go 数组的长度不可改变,在特定场所中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
2, 定义切片
    你可以声明一个未指定大小的数组来定义切片
        var identifier []type
    切片不需要说明长度
    或使用make()函数来创建切片
        var slice1 []type = make([]type,len)
        也可以简写为
            slice1 := make([]type,len)
    也可以指定容量,其中capacity为可选参数
        make([]T,length,capacity)
    这里 len 是数组的长度并且也是切片的初始长度。
3, 切片初始化
    s := [] int{1,2,3}
    直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3,其cap=len=3
    s := arr[:]
    初始化切片s,是数组arr的引用
    s := arr[starIndex:endIndex]
    将arr中从下标startIndex 到 endIndex-1下的元素创建为一个新的切片
    s := arr[startIndex:]
    s := arr[:endIndex]
    s1 := s[startIndex:endIndex]
    通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片
4, len() 和 cap() 函数
    切片是可索引的,并且可以由len() 方法获取长度。
    切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
    slice01.go
        package main

        import "fmt"

        func main() {
            var numbers = make([]int,3,7)
            printSlice(numbers)
        }

        func printSlice(x []int)  {
            fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
        }
5, 空(nil)切片
    一个切片在未初始化之前默认为nil,长度为0
    slice02.go
        package main

        import "fmt"

        func main() {
            var numbers []int
            printSlice(numbers)
            if(numbers == nil){
                fmt.Printf("切片是空的")
            }
        }

        func printSlice(x []int)  {
            fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
        }
6, 切片截取
    可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound]
    slice03.go
        package main

        import "fmt"

        func main() {
            numbers :=[]int{0,1,2,3,4,5,6,7,8}
            printSlice(numbers)
            /* 打印原始切片 */
            fmt.Println("numbers == ", numbers)
            /* 打印子切片从索引1(包含)到索引4(不包含) */
            fmt.Println("numbers[1:4] == ",numbers[1:4])
            /* 默认下限为 0 */
            fmt.Println("numbers[:3] == ", numbers[:3])
            /* 默认上限为len(s) */
            fmt.Println("numbers[4:] == ",numbers[4:])
            numbers1 := make([]int,0,5)
            printSlice(numbers1)
            numbers2 := numbers[:2]
            printSlice(numbers2)
            numbers3 := numbers[2:5]
            printSlice(numbers3)
        }

        func printSlice(x []int)  {
            fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
        }
7, append() 和 copy() 函数
    如果想增加切片的容量,我们必须创建一个新的更大的切片把原分片的内容都拷贝过来。
    下面的代码描述了从拷贝切片的copy方法到向切片追加新元素的append方法。
    slice04.go
        package main

        import "fmt"

        func main() {
            var numbers []int
            printSlice(numbers)
            /* 允许追加空切片 */
            numbers = append(numbers,0)
            printSlice(numbers)
            /* 向切片添加一个元素 */
            numbers = append(numbers,1)
            printSlice(numbers)
            /* 同时添加多个元素 */
            numbers = append(numbers,2,3,4)
            printSlice(numbers)
            /* 创建切片 numbers1 是之前切片的两倍容量 */
            numbers1 := make([]int,len(numbers),(cap(numbers))*2)
            /* 拷贝 numbers 的内容到 numbers1 */
            copy(numbers1,numbers)
            printSlice(numbers1)

        }

        func printSlice(x []int)  {
            fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
        }
8, 补充:容量
    切片拥有长度和容量
    切片的长度是它所包含的元素个数
    切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
    切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!