Golang教程第4篇-指针类型、流程控制

1.指针类型

值类型,变量寸的的是一个值;指针存的是一个地址,表示如*int

获取变量的地址&a,这里a是一个变量,获取指针类型所指向的值使用*a

下面是一个例子,要求满足两点
1、声明一个指针并输出指针到终端
2、自定义一个函数,传递一个指针类型到函数中,在函数中修改指针指向的值,调用函数在终端输出修改前后的值
代码

package main

import (
    "fmt"
)

func Zhizhen(b *int) {
    *b = 10
}

func main() {
    var a int = 5
    var b *int
    b = &a
    
    fmt.Printf("%T %v\n",b,b)
    fmt.Ptintf("修改前的值:%d\n",a)
    Zhizhen(b)
    fmt.Printf("修改后的值:%d\n",a)
}

编译执行
05go22

下面是老师给的一个例子

package main

import (
    "fmt"
)

func Modify(p *int) {
    *p = 100900
    return
}

func main() {
    var a int = 10
    var p *int
    
    p = &a
    fmt.Println(a)
    
    *p = 100
    fmt.Println(a)
    
    var b int = 999
    p = &b // 改变指针p的值
    *p = 5 // 改变指针p指向的值
    fmt.Println(a)
    fmt.Println(b)
    
    Modify(&a)
    fmt.Println(a)
}

编译执行
05go23

2.if

其基本格式有以下几种

// 格式一
if condition {
    ...
}

// 格式二
if condition {
    ...
} else {
    ...
}

// 格式三
if condition1 {
    ...
} else if condition2 {
    ...
} else {
    ...
}

有两点注意,一是else 或else if必须跟在上一个语句块结尾花括号后面,且有空格;二是else if语句可以写多个

例子:从终端输入一个字符串,转换成整型输出到终端,如果报错,输出报错内容

package main

import (
    "fmt"
    "strconv"
)

func main() {
    var str string
    fmt.Scanf("%s",&str)
    number,err := strconv.Atoi(str)
    if err != nil {
        fmt.Println("can not conver into int.",err)
        return 
    }
    fmt.Println(str)
}

3.switch

switch格式

// 写法一
var a int = 5 // 这里以一个整型为例,下面写法也是
stitch a {
case value1:
    ...
case value2:
    ....
...
default:
    ....
}

// 写法二
var a int = 5
switch a {
case var1,var2,var3...,varn:
    ...
case var1,var2,var3,...,varn:
    ...
default:
    ...
}

// 写法三  
var a int = 5
switch {
    case condition1:
        ...
    case condition2:
        ...
    default:
        ...
}

// 写法四
switch i := 0; {
    case condition1:
        ...
    case condition2:
        ...
    default:
        ...    
}

例:

package main

import (
    "fmt"
)

func main() {
    var a int = 10
    
    switch a {
    case 0:
        fmt.Println("a is equal 0")
    case 10:
        fmt.Println("a is equal 10")
    default:
        fmt.Println("error")
    }
}

switch语句与for、if不一样,它没有break,当匹配到条件执行完相应语句之后就跳出switch,不会继续执行switch后面的语句,即默认不会穿透整个switch语句块,如果要强制往下执行,需要在匹配输出的语句块最后加上关键字fallthrough

针对写法三看看下面这个例子
写一个程序,要求生成一个小于100的随机数,然后猜这个数,猜对了输出“猜对了到终端”,猜错了,输出“大于这个数”或者“小于这个数”

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    n := rand.Intn(100)
    
    var flag bool
    var input int
    fmt.Scanf("%d\n",&input)
    
    for {
        switch {
        case input == n:
            fmt.Print("猜对了")
            flag = true
        case input > n:
            fmt.Println("input大于n")
        case input < n:
            fmt.Println("input小于n")
        }
    }
    
    if flag {
        break
    }    
}

写这个程序的思路是这样的:

  • 先生成一个小于100随机数
  • 从终端输入一个数
  • 比较输入的数与随机数是否,打印不同情况下的输出
  • 上面的这个比较会有多次,这个多次不确定,需要使用无限循环
  • 判断对了,就需要跳出循环

4.for

格式一:

for i := value1;i < value2;i++ {
    ...
}

例子1:

package main

import (
    "fmt"
)

// Ainput is a function for 计算每一行输出的字符串
func Ainput(i int) string {
    var str string = "A"
    var strall string
    for j := 0;j < i;j++ {
        strall += str
    }
    return strall
}

func main() {
    for i := 1;i < 6;i++ {
        str := Ainput(i)
        fmt.Println(str)
    }
}

编译执行
05go24

下面还有两种写法作为参考比较
写法一:

package main

import (
    "fmt"
)

func Ainput(i int) {
    var str string = "A"
    var strall string
    for j := 0;j < i;j++ {
        starall = strall + str
    }
    fmt.Println(strall)
}

func main() {
    for i := 1;i < 6;i++ {
        Ainput(i)
    }
}

写法二:

package main

import (
    "fmt"
)

func Ainput(n int) {
    for i := 0;i < n;i++ {
        for j := 0;j < i;j++ {
            fmt.Printf("A")
        }
        fmt.Println()
    }
}

func main() {
    Ainput(5)
}

这三个写法大同小异,区别在于是在调用函数里就输出还是在main函数输出,main函数输出就需要返回值,这里推荐写法二,更简洁

格式二:

for condition {
    ...
}

格式三:

for i,v := range str { 
    ...
}

来看一个例子

package main

import (
    "fmt"
)

func main() {
    str := "hello world 中国"
    for i,v := range str {
        fmt.Printf(index[%d] value[%c] len[%d]\n",i,v,len([]byte(string(v))))
    }

编译执行
05go25

上面在输出每一个字符长度的时候作了类型转换,for range遍历字符串的时候获取的变量v的类型非字符型非字符串型,但是可以通过类型转换时期成为字符型[]byte(string(v))

再来看一个例子

package main

import (
    "fmt"
)

func main() {
    str := "hello world 中国"
    for i,v := range str {
        if i < 2 {
            continue
        }
        if i > 3 {
            break
        }
        fmt.Printf("index[%d] value[%d] len[%d]\n",i,v,len([]byte(string(v))))
    }
}

编译执行
05go26

这里利用continue与break的特点来有选择的输出

5.goto与label

goto与label是一种定位符

package main

import (
    "fmt"
)

func main() {
label1:
    for i := 1;i < 6;i++ {
        for j := 0;j < i;j++ {
            if i == 4 {
                continue label1
            }
            fmt.Println(i,j)
          }
     }
}

编译执行
05go27

再来看一个例子

package main

func main() {
    i := 0
HERE:
    print(i)
    if i == 6 {
        return
    }
    i++
    goto HERE
}

相当于使用goto实现了一个for循环