Go面试题

1. 13.1 Go练习题

创建一个goroutine与主线程按顺序相互发送信息若干次 且打印

slice在自动扩容后,内存地址变化

goroutine与闭包的坑

练习题汇总

package main

func main() {
    //写⼀一个程序,获取当前时间,并格式化成 2017/06/15 08:05:00形式
    //写⼀一个程序,统计⼀一段代码的执⾏行行耗时,单位精确到微秒。
    //计算99乘法表
    //写⼀一个程序,对包含中⽂文的字符串串进⾏行行逆序。
    //写⼀一个程序,判断⼀一个字符串串是否是回⽂文。
    //求1到100之内的所有质数,并打印到屏幕上
    /*
        打印出所有的“⽔水仙花数”,所谓“⽔水仙花数”是指⼀一个三位数,其各位数字⽴立⽅方和 等于该数本身。例例如:153是⼀一个“⽔水仙花数”,因为153=1的三次⽅方+5的三次⽅方 +3的三次⽅方。求100到1000之间的所有⽔水仙花数,
    */
    //输⼊入⼀一⾏行行字符,分别统计出其中英⽂文字⺟母、空格、数字和其它字符的个数。
    //实现一个插⼊入排序
    //实现一个选择排序
    //实现一个冒泡排序
    //求数组所有元素之和
    /*
        如下结果输出什么
        func main() {
         var sa = make ([]string,5,10);
         for i:=0;i<10;i++{
           sa=append(sa,fmt.Sprintf("%v",i))
         }
         fmt.Println(sa)
    */
    //用golangsort包对数组排序
    /*
        实现⼀一个密码⽣生成⼯工具,支持以下功能
        1.用户可以通过-l指定⽣生成密码的⻓长度
        提示:可以⽤用标准包 “flag”解析命令⾏行行参数
        2. ⽤用户可以通过-t指定⽣生成密码的字符集,⽐比如-t num⽣生成全数字的密码
        -t char ⽣生成包含全英⽂文字符的密码,-t mix包含⽣生成数字和英⽂文的密码,
        -t advance ⽣生成包含数字、英⽂文以及特殊字符的密码
    */
    //写⼀一个程序,获取⼀一个变量量的地址,并打印到终端
    //写⼀一个函数,传⼊入⼀一个int类型的指针,并在函数中修改所指向的值
    //写⼀一个程序,统计⼀一个字符串串每个单词出现的次数。⽐比如: s = “how do you do” 输出 how = 1 do = 2 you = 1
    //写⼀一个程序,实现学⽣生信息的存储,学⽣生有id、年年龄、分数等信息。需要⾮非常⽅方 便便的通过id查找到对应学⽣生的信息。

    /*
        你有50枚⾦金金币,需要分配给以下⼏几个⼈人:Matthew, Sarah, Augustus, Heidi, Emilie,Peter, Giana, Adriano, Aaron, Elizabeth。分配规则如下所示:
            a. 名字中包含’a’或’A’: 1枚⾦金金币 b. 名字中包含’e’或’E’: 1枚⾦金金币 c. 名字中包含 ‘i’或’I’: 2枚⾦金金币 d. 名字中包含’o’或’O’: 3枚⾦金金币 e. 名字中包含’u’或’U’: 5枚⾦金金币
            写⼀一个程序,计算每个⽤用户分到了了多少⾦金金币,以及最后剩余多少⾦金金币?
    */
    /*
        实现⼀一个简单的学⽣生管理理系统,每个学⽣生有分数、年年级、性别、名字等 字段,⽤用户可以在控制台添加学⽣生、修改学⽣生信息、打印所有学⽣生列列表的功能
    */
    /*
     实现⼀一个简单的学⽣生管理理系统,每个学⽣生有分数、年年级、性别、名字等 字段,⽤用户可以在控制台添加学⽣生、修改学⽣生信息、打印所有学⽣生列列表的功能。使⽤用⾯面向对象的⽅方式实现!
    */
    /*
      实现⼀一个简易易的计算器器,⽀支持加减乘除以及带括号的计算表达式,⽤用户从终端输⼊入表达式, 程序输出计算结果。
    */
    /*
       实现一个类似 linux的tree 命令,输入tree.exe能够以树状的形式当前目录下所有文件,如下 所示。
    */
}
 
 

1. 13.2 Go练习题答案

练习题1:

创建一个goroutine与主线程按顺序相互发送信息若干次 且打印

package temp

import "fmt"

//创建一个goroutine与主线程按顺序相互发送信息若干次 且打印
var c chan string //声明一个string管道
func Pingpong() {
    i := 0
    for {
        fmt.Println(<-c) //打印管道中取出的数据
        c <- fmt.Sprintf("From pingpong: say hi ,%d", i)
        i++
    }
}
func main() {
    c = make(chan string) //初始化管道内存
    //协程执行函数
    go Pingpong()
    //主函数循环打印十次
    for i := 0; i < 10; i++ {
        c <- fmt.Sprintf("From main: say hi,%d", i)
        fmt.Println(<-c)
    }
}

slice在自动扩容后,内存地址变化

package main

import (
    "fmt"
)

/*
//有关slice的坑,slice在自动扩容后,内存地址已经变了
func Pingpong(s []int) {
    s = append(s, 3)
}

func main() {
    s := make([]int, 0)
    fmt.Println(s)
    Pingpong(s)
    fmt.Println(s)
}
*/

//提供返回值,将append这个心的切片返回
func Pingpong(s []int) []int {
    s = append(s, 3)
    return s
}

func main() {
    s := make([]int, 0) //初始容量是0,append后切片地址变了
    fmt.Printf("%p %v\n", s, s)
    s = Pingpong(s)
    fmt.Printf("%p %v\n", s, s)
}

goroutine与闭包的坑

package main

import (
    "fmt"
)

func main() {
    s := []string{"a", "b", "c"}
    for _, v := range s {
        //此时func()是个闭包函数,变量v是c
        //可以接收一个参数,作为值拷贝
        go func(v) {
            fmt.Println(v)
        }(v)
    }
    select {} //用select阻塞main退出
}

写⼀一个程序,获取当前时间,并格式化成 2017/06/15 08:05:00形式

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    //通过now.Format格式化时间
    fmt.Println(now.Format("2006/01/02 15:04:05"))
}

写⼀一个程序,统计⼀一段代码的执⾏行行耗时,单位精确到微秒。

package main

import (
    "fmt"
    "time"
)

/*
1秒=1000毫秒(ms)

1秒=1,000,000 微秒(μs)

1秒=1,000,000,000 纳秒(ns)
*/
func Task() {
    start := time.Now().UnixNano()   //返回当前的纳秒数
    time.Sleep(5 * time.Millisecond) //睡眠5毫秒
    end := time.Now().UnixNano()
    cost := (end - start) / 1000 //换算成us微秒
    fmt.Printf("do task spend:%d us \n", cost)
}

func main() {
    Task()
}

99乘法表

func testMulti() {
    //有9行,每行有同等数的列
    //i代表行
    for i := 1; i < 10; i++ {
        //j代表列,从1开始,等同于行数
        for j := 1; j <= i; j++ {
            fmt.Printf("%d * %d = %d\t", j, i, j*i)
        }
        fmt.Println()
    }
}

写⼀一个程序,对英⽂文字符串串进⾏行行逆序

func testReverString() {
    var str = "hello超哥"
    //对字符串操作,反转含有中文的字符串,转化为rune切片,rune切片存的是单个字符,而byte切片存单个字节
    var r []rune = []rune(str)
    //遍历rune切片,每次交换头尾2个值,因此只需要交换长度的一半
    fmt.Println(len(r)) //默认rune切片长度是7
    fmt.Printf("%c\n", r)
    for i := 0; i < len(r)/2; i++ {
        //因为索引是从0开始,因此长度要减一
        //每次交换,头尾交换数据,交换5次
        r[len(r)-i-1], r[i] = r[i], r[len(r)-i-1] //交换头尾,r[len(r)-i-1]是尾巴索引,交换给头索引,也就是9换0,8换1,7换2,6换3,5换4
        fmt.Printf("%c\n", r)
    }
    str = string(r)
    fmt.Printf("%s\n", str)
}

写⼀一个程序,判断⼀一个字符串串是否是回⽂文。

func isHuiwen(str string) bool {
    //对字符串操作,反转含有中文的字符串,转化为rune切片,rune切片存的是单个字符,而byte切片存单个字节
    var r []rune = []rune(str)
    //遍历rune切片,每次交换头尾2个值,因此只需要交换长度的一半
    fmt.Println(len(r)) //默认rune切片长度是7
    for i := 0; i < len(r)/2; i++ {
        //因为索引是从0开始,因此长度要减一
        //每次交换,头尾交换数据,交换5次
        r[len(r)-i-1], r[i] = r[i], r[len(r)-i-1] //交换头尾,r[len(r)-i-1]是尾巴索引,交换给头索引,也就是9换0,8换1,7换2,6换3,5换4
    }
    str1 := string(r)
    if str1 == str {
        return true
    }
    //这里由于 golint对代码的静态检查,因此不需要写else,直接return false即可
    return false

}

func main() {
    b := isHuiwen("上海自来水来自海上")
    fmt.Println(b)
}

求1到100之内的所有质数,并打印到屏幕上

//质数p,又称素数(prime),指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数
//求1-100的质数,
func justify(n int) bool {
    //对传入的数值判断
    //如果小于等于1直接判断false
    if n <= 1 {
        return false
    }
    //循环判断2-100是否为素数
    //此时i是除数,n是被除数
    for i := 2; i < n; i++ {
        //如果余数可以为0,代表可以被整除,也就不符合素数的概念
        if n%i == 0 {
            return false
        }
    }
    return true
}
func test() {
    //循环1-200的数,排除1
    for i := 2; i < 100; i++ {
        if justify(i) == true {
            fmt.Printf("%d is prime\n", i)
        }
    }
}

func main() {
    test()
}

求100-1000的水仙花数

func isShuixianhua(n int) bool {
    //个位数,一个数对10求模就是获取该数的个位数,例如153%10的值是3
    first := n % 10
    //十位数
    second := (n / 10) % 10
    //百位数
    third := (n / 100) % 10
    //水仙花数
    sum := first*first*first + second*second*second + third*third*third
    if sum == n {
        return true
    }
    return false
}
func main() {
    //遍历100-1000之间
    for i := 100; i < 1000; i++ {
        if isShuixianhua(i) == true {
            fmt.Printf("%d 是水仙花数\n", i)
        }
    }
}

输⼊入⼀一⾏行行字符,分别统计出其中英⽂文字⺟母、空格、数字和其它字符的个数

func calc(str string) (charCount int, numCount int, spaceCount int, otherCount int) {
    //遍历统计字符串,需要转换为rune切片,进行挨个判断,如果是某一个类型,计数器就加一
    utfChars := []rune(str)
    for i := 0; i < len(utfChars); i++ {
        if utfChars[i] >= 'a' && utfChars[i] <= 'z' || utfChars[i] >= 'A' && utfChars[i] <= 'Z' {
            charCount++
            continue
        }

        if utfChars[i] >= '0' && utfChars[i] <= '9' {
            numCount++
            continue
        }

        if utfChars[i] == ' ' {
            spaceCount++
            continue
        }

        otherCount++
    }
    return
}
func main() {
    var str string = "我爱北京天安门  10000年"
    charCount, numCount, spCount, other := calc(str)
    fmt.Printf("char count:%d | num count:%d | sp count:%d | other:%d\n", charCount, numCount, spCount, other)
}

插入排序

//插入排序
func insert_sort(a [8]int)[8]int{
    for i:=1;i<len(a);i++{
        for j:=i;j>0;j--{
            if a[j]<a[j-1]{
                a[j],a[j-1]=a[j-1],a[j]
            }else {
                break
            }
        }
    }
    return a
}

选择排序

func select_sort(a [8]int)[8]int{
    for i:=0;i<len(a);i++{
        for j:=i+1;j<len(a);j++{
            if a[j]<a[i]{
                a[i],a[j]=a[j],a[i]
            }
        }
    }
    return a
}

冒泡排序

func bubble_sort(a [8]int) [8]int {
    for i := 0; i < len(a); i++ {
        for j := 0; j < len(a)-i-1; j++ {
            if a[j] > a[j+1] {
                a[j], a[j+1] = a[j+1], a[j]
            }
        }
    }
    return a
}

求数组所有元素之和


//求数组所有元素之和
func sumArray(r [10]int) int {
    var sum int
    for _, v := range r {
        sum += v
    }
    return sum
}

//随机生成一个长度10的数组
func testArray() {
    //通过随机数种子生成值,否则rand.Intn总是一个固定的随机数
    rand.Seed(time.Now().Unix())
    var b [10]int
    for i := 0; i < len(b); i++ {
        b[i] = rand.Intn(100)
    }
    fmt.Println(b)
    sum := sumArray(b)
    fmt.Println(sum)
}

func main() {
    testArray()
}

判断如下结果的输出信息

func main() {
    var sa = make([]string, 5, 10)
    fmt.Println(sa) //默认有5个空元素的切片
    //循环写入十个元素,sa切片自动扩容
    for i := 0; i < 10; i++ {
        //追加是从第六个元素追加
        sa = append(sa, fmt.Sprintf("%v", i))
        fmt.Printf("长度%d,容量%d 内容%v\n", len(sa), cap(sa), sa)
    }
    fmt.Println(sa)
}

结果

yugoMBP:lesson1 yuchao$ go run main.go 
[    ]
长度6,容量10 内容[     0]
长度7,容量10 内容[     0 1]
长度8,容量10 内容[     0 1 2]
长度9,容量10 内容[     0 1 2 3]
长度10,容量10 内容[     0 1 2 3 4]
长度11,容量20 内容[     0 1 2 3 4 5]
长度12,容量20 内容[     0 1 2 3 4 5 6]
长度13,容量20 内容[     0 1 2 3 4 5 6 7]
长度14,容量20 内容[     0 1 2 3 4 5 6 7 8]
长度15,容量20 内容[     0 1 2 3 4 5 6 7 8 9]
[     0 1 2 3 4 5 6 7 8 9]

用golangsort包对数组排序


func pkgSort() {
    // s1 := []int{3, 6, 5, 7, 8, 1} //声明初始化切片
    var a [5]int = [5]int{5, 4, 3, 2, 1}
    sort.Ints(a[:])
    fmt.Println("a:", a)

    var b [5]string = [5]string{"ac", "ec", "be", "fa", "ii"}
    sort.Strings(b[:])
    fmt.Println("b:", b)

    var c [5]float64 = [5]float64{29.38, 22.32, 0.8, 99191.2}
    sort.Float64s(c[:])

    fmt.Println("c:", c)
}

实现⼀一个密码⽣生成⼯工具,支持以下功能 用户可以通过-l指定⽣生成密码的⻓长度 提示:可以⽤用标准包 “flag”解析命令⾏行行参数

用户可以通过-t指定⽣生成密码的字符集,⽐比如 -t num⽣生成全数字的密码 -t char ⽣生成包含全英⽂文字符的密码, -t mix包含⽣生成数字和英⽂文的密码, -t advance ⽣生成包含数字、英⽂文以及特殊字符的密码

package main

import (
    "flag"
    "fmt"
    "math/rand"
    "time"
)

var (
    length  int
    charset string
)

//密码策略,数字字母,特殊符号
const (
    NumStr  = "0123456789"
    CharStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    SpecStr = "+=-@#~,.[]()!%^*$"
)

//解析用户输入
func parseArgs() {
    //传入整数,参数密码长度,参数名字,参数长度默认值,帮助信息
    flag.IntVar(&length, "l", 16, "-l 生成密码的长度")
    //传入的是字符串,解析哪些参数
    // 注意``用法,保证字符串原样输出
    flag.StringVar(&charset, "t", "num",
        `-t 制定密码生成的字符集, 
    num:只使用数字[0-9], 
    char:只使用英文字母[a-zA-Z], 
    mix: 使用数字和字母, 
    advance:使用数字、字母以及特殊字符`)
    //指定选项之后,确认解析
    flag.Parse()
}

func test1() {
    for i := 0; i < len(CharStr); i++ {
        //如果字符串不为空,就输出信息
        if CharStr[i] != ' ' {
            fmt.Printf("%c", CharStr[i])
        }
    }

}

//生成密码 函数
func generatePasswd() string {
    //初始化密码,存为切片,字符是byte,因此是[]byte,容量是用户指定的
    var passwd []byte = make([]byte, length, length)
    var sourceStr string
    //如果类型是num,返回数字常量,密码就是一堆数字
    if charset == "num" {
        sourceStr = NumStr
        //或者是一个字符
    } else if charset == "char" {
        sourceStr = CharStr
        //或者是混合型的
    } else if charset == "mix" {
        sourceStr = fmt.Sprintf("%s%s", NumStr, CharStr)
        //如果是高级的,数字,字母,特殊符号
    } else if charset == "advance" {
        sourceStr = fmt.Sprintf("%s%s%s", NumStr, CharStr, SpecStr)
        //如果用户输入错了,则默认返回数字密码
    } else {
        sourceStr = NumStr
    }
    //打印原始字符信息
    // fmt.Println("source:", sourceStr)
    //判断用户输入参数 -l
    for i := 0; i < length; i++ {
        //循环取得随机数
        index := rand.Intn(len(sourceStr))
        //将随机数写入到密码切片中
        passwd[i] = sourceStr[index]
    }
    return string(passwd)
}

func main() {
    //随机数种子
    rand.Seed(time.Now().UnixNano())
    //解析用户输入的参数
    parseArgs()
    //什么都不加,显示默认参数
    // fmt.Printf("length:%d charset:%s\n", length, charset)
    //生成随机数密码
    passwd := generatePasswd()
    fmt.Println(passwd)
}

写⼀一个函数,传⼊入⼀一个int类型的指针,并在函数中修改所指向的值

func testPtr(n *int) {
    *n = 666
}
func main() {
    n := 200
    testPtr(&n)
    fmt.Println(n)
}

写⼀一个程序,统计⼀一个字符串串每个单词出现的次数。⽐比如: s = “how do you do” 输出 how = 1 do = 2 you = 1


//单词次数统计,返回map类型,key=单词,value=次数
func wordCount(str string) map[string]int {
    //初始化map,存放结果
    var result = make(map[string]int, 128)
    //对用户的输入,通过空格分割,区分单词,返回值是个切片
    words := strings.Split(str, " ")
    //遍历切片
    for _, v := range words {
        //ok是对map中的数据判断,count是map的值,也就是统计单词的次数
        count, ok := result[v]
        //如果不存在,添加一次统计
        if !ok {
            result[v] = 1

        } else {
            //如果已经存在了,value的数值+1
            result[v] = count + 1
        }
    }
    return result
}
func main() {
    str := "I am a boy. I have a apple."
    result := wordCount(str)
    //%v 输出默认值  %#v 输出完全的go语法格式
    fmt.Printf("result:%#v\n", result)
}

写⼀一个程序,实现学⽣生信息的存储,学⽣生有id、年年龄、分数等信息。需要⾮非常⽅方 便便的通过id查找到对应学⽣生的信息。


func testInterface() {
    //空接口可以接受任意值
    var a interface{}
    var b int = 100
    var c float32 = 1.2
    var d string = "hello"

    a = b
    fmt.Printf("a=%#v %T\n", a, a)

    a = c
    fmt.Printf("a=%#v %T\n", a, a)

    a = d
    fmt.Printf("a=%#v %T\n", a, a)
}

//写⼀一个程序,实现学⽣生信息的存储,学⽣生有id、年年龄、分数等信息。需要⾮非常⽅方 便便的通过id查找到对应学⽣生的信息。
func studentStore() {
    /*声明map类型,用它存储k-v形式数据 最合适不过
    格式
    学号id [年纪:18 id:1 名字:阿狗 socre:99.9]
    转化为map
    */
    //有一处map的类型是interface{},可以存储任何类型值,如int,string,float
    //初始化第一层的map,注意内层map还需继续初始化方可使用
    var stuMap = make(map[int]map[string]interface{}, 16)
    // //创建一条学生信息
    // id := 1
    // name := "阿狗"
    // score := 88.9
    // age := 18
    // //插入第一个学生的数据,如果学生不存在,就插入数据,必须得初始化方可使用
    // value, ok := stuMap[id]
    // //如果插入失败,是因为要对map进行初始化才能使用
    // if !ok {
    //     value = make(map[string]interface{}, 8)
    // }
    // value["name"] = name
    // value["id"] = id
    // value["score"] = score
    // value["age"] = age
    // //设置第一条数据
    // stuMap[id] = value
    // fmt.Printf("stuMap: %v\n", stuMap)

    //循环十条记录写入
    for i := 0; i < 10; i++ {
        value, ok := stuMap[i]
        if !ok {
            //如果值不存在,必须要初始化
            value = make(map[string]interface{}, 8)
        }
        //Sprintf接收格式化输出,返回字符串
        value["name"] = fmt.Sprintf("stu%d", i)
        value["id"] = i
        //返回随机的浮点数据
        value["score"] = rand.Float32() * 100.0
        value["age"] = rand.Intn(100) //随机返回100以内的年纪数字
        stuMap[i] = value
    }
    fmt.Println()
    //遍历取出所有学生成绩
    for k, v := range stuMap {
        fmt.Printf("学生id=%d 学生信息=%v\n", k, v)
    }
    //学生6号的信息
    info, ok := stuMap[6]
    if ok {
        fmt.Printf("学生%d号的 姓名:%s 成绩:%f 年纪:%d", info["id"], info["name"], info["score"], info["age"])
    }
    fmt.Println()
}

func main() {
    //testInterface()
    studentStore() //所有学生成绩
    //取出学生成绩
}

你有50枚⾦金金币,需要分配给以下⼏几个⼈人:Matthew, Sarah, Augustus, Heidi, Emilie,Peter, Giana, Adriano, Aaron, Elizabeth。

分配规则如下所示: a. 名字中包含’a’或’A’: 1枚⾦金金币 b. 名字中包含’e’或’E’: 1枚⾦金金币 c. 名字中包含 ‘i’或’I’: 2枚⾦金金币 d. 名字中包含’o’或’O’: 3枚⾦金金币 e. 名字中包含’u’或’U’: 5枚⾦金金币 写⼀一个程序,计算每个⽤用户分到了了多少⾦金金币,以及最后剩余多少⾦金金币?

package main

import "fmt"

//定义50个金币
var (
    coins = 50
    //用户信息存入一个切片,声明且初始化
    users = []string{
        "Matthew", "Sarah", "Augustus", "Heidi", "Emilie",
        "Peter", "Giana", "Adriano", "Aaron", "Elizabeth",
    }
    //分配distribution,根据用户个数分配
    distribution = make(map[string]int, len(users))
)

//计算金币,参数用户名字,计算个人的金币数量
func calcCoin(username string) int {
    var sum int = 0
    for _, char := range username {
        switch char {
        case 'a', 'A':
            sum++
        case 'e', 'E':
            sum++
        case 'i', 'I':
            sum += 2
        case 'o', 'O':
            sum += 3
        case 'u', 'U':
            sum += 5
        }
    }
    return sum
}

//分配金币
func dispathchCoin() int {
    var left = coins //定义剩余金币数
    //遍历users切片,计算金币
    for _, username := range users {
        allCoin := calcCoin(username)
        //计算剩余金币
        left -= allCoin
        value, ok := distribution[username]
        if !ok {
            distribution[username] = allCoin
        } else {
            distribution[username] = value + allCoin
        }
    }
    return left
}

func main() {
    left := dispathchCoin() //剩余金币数
    //遍历map
    for username, coin := range distribution {
        fmt.Printf("用户:\t%s\t拥有\t%d\t金币\n", username, coin)
    }
    fmt.Printf("剩余金币总数:%d\n", left)
}

Go作用域的坑,请说出如下输出

package main

import (
    "fmt"
)

//全局变量
var (
    Ga int = 99
)

const (
    v int = 199
)

func GetGa() func() int {

    if Ga := 55; Ga < 60 {
        fmt.Println("GetGa if 中:", Ga)
    }

    for Ga := 2; ; {
        fmt.Println("GetGa循环中:", Ga)
        break
    }
    //这里用全局变量
    fmt.Println("GetGa函数中:", Ga)
    //闭包函数,匿名函数func()对全局Ga的引用,第一次调用是99+1,第二次是100+1,第三次是101+1,第四次是102+1
    return func() int {
        Ga += 1
        return Ga
    }
}

func main() {
    Ga := "string"
    fmt.Println("main函数中:", Ga)

    b := GetGa()
    fmt.Println("main函数中:", b(), b(), b(), b())

    v := 1 //main函数体中局部变量
    //隐式代码块,有自己局部作用域
    {
        v := 2
        fmt.Println(v)
        {
            v := 3
            fmt.Println(v)
        }
    }
    fmt.Println(v)
}

结果

yugoMBP:golesson yuchao$ go run main.go 
main函数中: string
GetGa if 中: 55
GetGa循环中: 2
GetGa函数中: 99
main函数中: 100 101 102 103
2
3
1

解释

Ga作为全局变量纯在是int类型,值为99;而在main()中时,Ga通过简式声明 := 操作,是string类型,值为string。在main()中,v很典型地体现了在“{}”花括号中的作用域问题,每一层花括号,都是对上一层的屏蔽。而闭包函数,GetGa()返回的匿名函数,赋值给b,每次执行b(),Ga的值都被记忆在内存中,下次执行b()的时候,取b()上次执行后Ga的值,而不是全局变量Ga的值,这就是闭包函数可以使用包含它的函数内的变量,因为作为代码块一直存在,所以每次执行都是在上次基础上运行。
简单总结如下:
有花括号"{ }"一般都存在作用域的划分;
:= 简式声明会屏蔽所有上层代码块中的变量(常量),建议使用规则来规范,如对常量使用全部大写,而变量尽量小写;
在if等语句中存在隐式代码块,需要注意;
闭包函数可以理解为一个代码块,并且他可使用包含它的函数内的变量;

注意,简式变量只能在函数内部声明使用,但是它可能会覆盖函数外全局同名变量。而且你不能在一个单独的声明中重复声明一个变量,但在多变量声明中这是允许的,而且其中至少要有一个新的声明变量。重复变量需要在相同的代码块内,否则你将得到一个隐藏变量。
如果你在代码块中犯了这个错误,将不会出现编译错误,但应用运行结果可能不是你所期望。所以尽可能避免和全局变量同名。
 
 

1. 13.3 Go章节练习题

练习1:定义1个整数,1个小数,访问变量,打印数值和类型,更改变量的数值,打印数值

练习2:同时定义3个整数,

练习3:同时定义3个字符串

练习4:定义变量后,没有初始值,直接访问变量?

练习5:尝试定义全局变量

练习6:常量组中定义常量,如果没有赋值和上一行一致,写法?

package main

import "fmt"

//全局变量,函数体外
var (
    addr  string
    score float64
)

func main() {
    //局部变量,简短声明赋值
    i := 100
    f := 99.9
    fmt.Printf("类型:%T    值%v\n", i, i)
    fmt.Printf("类型:%T    值%v\n", f, f)

    //同时定义三个整数
    n1, n2, n3 := 1, 2, 3
    fmt.Println(n1, n2, n3)
    s1, s2, s3 := "断剑重铸之日", "骑士归来之时", "稳住我能carry"
    fmt.Println(s1, s2, s3)
    fmt.Println(s2)
    fmt.Println(s3)

    //定义变量,默认值,值类型可以修改,引用类型nil不得直接使用
    var name string
    fmt.Println(name)
    var age int
    fmt.Println(age)
    var m map[string]string
    fmt.Println(m)

    //读取全局变量
    addr = "昌平沙河"
    score = 99.99
    fmt.Println(addr)
    fmt.Println(score)

    fmt.Println(".........我是分割线.......")
    //常量定义
    const (
        sunday = iota
        Monday
        Tuesday
        Wedensday = "星期三"
        Thursday  = "星期四"
        Friday    = iota
        Saturday
    )
    fmt.Println(sunday)
    fmt.Println(Tuesday)
    fmt.Println(Friday)
    fmt.Println(Saturday)
}

1.每种基本类型的变量,各声明5个变量,并打印变量的数值,以及类型。

2.声明几个常量。

3.交换2个变量的值。

4.定义一个四位数的整数,分别获取各个位数的值

5.让用户输入账号密码, 并且接受用户账号密码

package main

import "fmt"

func main() {
    s1 := "我是字符串" //string
    b1 := 'w'
    var b2 byte = 'w' //byte是uint8的别名
    var b3 rune = '于' //rune是int32的别名,字符本质存的是字节码
    f1 := 123.45
    i1 := 12345678
    b4 := true
    b5 := false
    fmt.Printf("%T %v\n", s1, s1)
    fmt.Printf("%T %v %c\n", b1, b1, b1)
    fmt.Printf("%T %v %c\n", b2, b2, b2)
    fmt.Printf("%T %v %c\n", b3, b3, b3)
    fmt.Printf("%T %v \n", f1, f1)
    fmt.Printf("%T %v \n", i1, i1)
    fmt.Printf("%T %v\n", b4, b4)
    fmt.Printf("%T %v\n", b5, b5)
    fmt.Println("-----分割线----")
    //定义赋值常量
    const pi = 3.1415926
    const (
        Sunday = "星期天"
        Monday = 1
    )
    fmt.Println("-----分割线----")
    //交换变量的值
    a := 3
    b := 2
    a, b = b, a
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println("-----分割线----")
    //定义一个四位数的整数,分别获取各个位数的值
    num1 := 1983
    geWei := num1 % 10
    shiWei := (num1 / 10) % 10
    baiWei := (num1 / 100) % 10
    qianWei := (num1 / 1000) % 10
    fmt.Println(geWei)
    fmt.Println(shiWei)
    fmt.Println(baiWei)
    fmt.Println(qianWei)

    //键盘输入账号密码且打印
    var username string
    var password string
    fmt.Print("输入账号:")
    fmt.Scan(&username)
    fmt.Print("输入密码:")
    fmt.Scan(&password)
    fmt.Printf("用户输入的账号%s,密码%s\n", username, password)
}

1.使用if语句完成:给定数字:如果为1,就输出星期一,如果为2,就输出星期二,以此类推,一直到7,输出星期日。如果是其他数字,就输出"错误信息"。

2.作业1改为switch方式

3.使用if语句完成:给定月份,输出该月属于哪个季节。3,4,5 春季 6,7,8 夏季 9,10,11 秋季 12, 1, 2 冬季

4.作业3改用switch方式

5.模拟登录,键盘上输入用户名和密码,如果用户名是admin密码是123,或者用户名是zhangsan密码是zhangsan123,都表示可以登录。否则打印登录失败

6.使用if语句完成:给定年龄,如果小于18岁,输出青少年,如果大于等于18并且小于30岁,输出青年,否则输出中老年。

7.用switch完成简单 "+-*/"计算器

8.随机猜数游戏

9.100以内,计算奇数和,偶数和

10.百钱买白鸡 百元百鸡,一百元钱买100只鸡,公鸡5元一只,母鸡3元一只,小鸡1元3个。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func testIf() {
    var num int
    fmt.Println("请输入数字:1-4")
    fmt.Scan(&num)
    if num == 1 {
        fmt.Println("星期一")
    } else if num == 2 {
        fmt.Println("星期二")
    } else if num == 3 {
        fmt.Println("星期三")
    } else if num == 4 {
        fmt.Println("星期四")
    } else {
        fmt.Println("输入有误,重新输入")
    }
}
func testSwitch() {
    var num int
    fmt.Println("请输入数字:1-4")
    fmt.Scan(&num)
    switch num {
    case 1:
        fmt.Println("星期一")
    case 2:
        fmt.Println("星期二")
    case 3:
        fmt.Println("星期三")
    case 4:
        fmt.Println("星期四")
    default:
        fmt.Println("输入有误,重新输入")
    }
}
func testIf2() {
    var num int
    fmt.Println("请输入月份")
    fmt.Scan(&num)
    if num == 3 || num == 4 || num == 5 {
        fmt.Println("春天来了,又到了...")
    } else if num == 6 || num == 7 || num == 8 {
        fmt.Println("夏天到了,又可以....")
    } else if num == 9 || num == 10 || num == 11 {
        fmt.Println("秋天到了,适合休息,秋游")
    } else if num == 12 || num == 1 || num == 2 {
        fmt.Println("春天到了,万物冬眠")
    } else {
        fmt.Println("输入月份有误")
    }
}
func testSwitch2() {
    var num int
    fmt.Println("请输入月份")
    fmt.Scan(&num)
    switch num {
    case 3, 4, 5:
        fmt.Println("春困")
    case 6, 7, 8:
        fmt.Println("夏乏")
    case 9, 10, 11:
        fmt.Println("秋天适合郊游")
    case 12, 1, 2:
        fmt.Println("冬眠")
    default:
        fmt.Println("输入月份有误")
    }
}
func userPwd() {
    var username string
    var pwd string
    fmt.Println("请输入用户名:")
    fmt.Scan(&username)
    fmt.Println("请输入密码:")
    fmt.Scan(&pwd)
    if username == "oldboy" && pwd == "oldboy666" {
        fmt.Println("登录成功")
    } else {
        fmt.Println("登录失败")
    }
}

func ageTest() {
    var age int
    fmt.Println("请输入你的年纪:")
    fmt.Scan(&age)
    if age < 18 {
        fmt.Println("你好,小老弟")
    } else if age > 18 && age < 30 {
        fmt.Println("你好,青年")
    } else {
        fmt.Println("你个遭老头子,坏得很")
    }
}
func switchCalc() {
    var num1 int
    fmt.Print("输入num1:")
    fmt.Scan(&num1)
    var num2 int
    fmt.Print("输入num2:")
    fmt.Scan(&num2)
    var oper string
    fmt.Println("输入运算符:")
    fmt.Scan(&oper)
    switch oper {
    case "+":
        fmt.Println(num1 + num2)
    case "-":
        fmt.Println(num1 - num2)
    case "*":
        fmt.Println(num1 * num2)
    case "/":
        fmt.Println(num1 / num2)
    default:
        fmt.Println("运算符有误")
    }
}
func caishuzi() {
    /*
        猜数游戏:
        step1:产生随机数
        step2:循环猜数
    */
    //1.产生系统的随机数
    rand.Seed(time.Now().UnixNano())
    randNum := rand.Intn(50)
    //fmt.Println(randNum)

    num := 0
    //2.猜,如果猜不对,一直循环
    for i := 0; num != randNum; i++ {
        fmt.Printf("第%d次输入数字:\n", i)
        fmt.Scan(&num)
        if num > randNum {
            fmt.Println("猜大了")
        } else if num < randNum {
            fmt.Println("猜小了")
        } else {
            fmt.Println("恭喜你,猜对了!!")
        }
    }
}

//100以内,计算奇数和,偶数和
func jiou() {
    //奇数
    num := 0
    num2 := 0

    for i := 0; i < 100; i++ {
        if i%2 == 0 {
            num += i
        }
        if i%2 == 1 {
            num2 += i
        }
    }
    fmt.Println("100以内偶数和:", num)
    fmt.Println("100以内奇数和:", num2)
}

/*
百钱买白鸡
百元百鸡,一百元钱买100只鸡,公鸡5元一只,母鸡3元一只,小鸡1元3个。
100元,一共买100只鸡
公鸡可买数量范围 [0,20]  数量a
母鸡可买数量范围 [0,33]      数量b
最多买100只鸡,所以不可能全部买小鸡,300只超量了
小鸡可买数量范围[100-a-b] 去掉a,b的数量,就是剩下小鸡的数量
*/

func ji() {
    for a := 0; a <= 20; a++ { //公鸡的数量
        for b := 0; b <= 33; b++ { //母鸡的数量
            c := 100 - a - b //小鸡的数量
            //所有组合可能性如下
            //fmt.Printf("公鸡数量%d 母鸡数量%d 小鸡数量%d\n", a, b, c)
            //如果三只鸡的钱总数是100 并且 没有剩余的钱,组合就正确了
            //公鸡价格5元一只,母鸡价格3元一只,小鸡数量3元一个,所以c/3等于价格
            //并且小鸡数量取余3,没有余数,代表没有零钱
            if a*5+b*3+c/3 == 100 && c%3 == 0 {
                fmt.Printf("百钱买白鸡:公鸡数量:%d\t,母鸡数量:%d\t,小鸡数量:%d\n", a, b, c)
            }
        }
    }
}
func main() {
    ji()
}

1.操场上有一群人,人数在100到200之间。三人一组多1人,四人一组多2人,五人一组多3人。问操场上共有多少人。

2.两个自然数x,y相除,商3余10,被除数,除数,商,余数的和是163,求被除数,除数

3.某数学竞赛中,参赛人数大约在380-450之间。比赛结果,全体考生的总平均分为76分,男生的平均分为75,女生的平均分为80.1,求男女生各有多少人。

4.给定一个数组,arr1 := [10] int{5,4,3,7,10,2,9,8,6,1},求数组中所有数据的总和。

5.二维数组的遍历

6.给定一个整型数组,长度为10。数字取自随机数。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

//操场人数
func playGround() {
    for i := 100; i <= 200; i++ {
        if i%3 == 1 && i%4 == 2 && i%5 == 3 {
            fmt.Println(i)
        }
    }
}

//
func test1() {
    //    两个自然数x,y相除,商3余10,被除数,除数,商,余数的和是163,求被除数,除数
    /*
        思路:
        自然数x,y加上商,余数总和是163
        条件商3余数10,那么去掉这个数,x+y的总和是150
    */
    for x := 0; x < 150; x++ {
        //y的值
        y := 150 - x
        if x/y == 3 && x%y == 10 {
            fmt.Printf("被除数%d 除数%d\n", x, y)
        }
    }
}

func student() {
    //某数学竞赛中,参赛人数大约在380-450之间。比赛结果,全体考生的总平均分为76分,男生的平均分为75,女生的平均分为80.1,求男女生各有多少人。
    /*
        思路,人数一共380-450之间    i
        求男生数量    x
        女生数量        y
        条件,全体人数平均分76,男生平均分75,女生平均分80.1
    */
    //嵌套循环计算
    for i := 380; i < 450; i++ {
        for x := 0; x < i; x++ {
            y := i - x
            //计算人数
            //总分数=男生分数+女生分数
            if float64(i*76) == float64(x*75)+float64(y)*(80.1) {
                fmt.Printf("男生人数:%d\t女生人数%d\t总人数%d\n", x, y, i)
            }
        }
    }
}

func test2() {
    //给定一个数组,arr1 := [10] int{5,4,3,7,10,2,9,8,6,1},求数组中所有数据的总和。
    arr1 := [10]int{5, 4, 3, 7, 10, 2, 9, 8, 6, 1}
    num := 0
    for _, v := range arr1 {
        num += v
    }
    fmt.Println("数组元素总和", num)
}

//二维数组
/*
二维数组:存储的是一维的一维
        arr :=[3][4]int
        该二维数组的长度,就是3。
        存储的元素是一维数组,一维数组的元素是数值
*/
func test3() {
    arr := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} //默认值    [[1 2 3 4] [0 0 0 0] [0 0 0 0]]
    fmt.Println(arr)
    //取出二维数组元素
    for _, v1 := range arr {
        for _, v2 := range v1 {
            fmt.Println("二维数组中的元素:", v2)
        }
    }
}

//给定一个整型数组,长度为10。数字取自随机数。
func makeArray() {
    /*
        给定一个整型数组,长度为10。数字取自随机数。
        [1,10]
    */
    //初始化数组
    arr := [10]int{}
    fmt.Println(arr)
    //随机数种子
    rand.Seed(time.Now().UnixNano())
    //循环生成写入元素,正常写入
    for i := 0; i < len(arr); i++ {

        x := 0
        //验证:x是否已经存储过了
        /*
         循环验证x是否已经存储,如果已经有,再取随机数,再验证,直到不重复
        */
        //循环验证
        for {
            //生成随机数
            x = rand.Intn(10) + 1 // 8
            flag := true          //true:代表不重复值可以用,false代表值重复,不可以使用
            //循环检测,次数依次少于元素个数
            for j := 0; j < i; j++ {
                //如果x元素已经存在,结束循环
                if x == arr[j] {
                    flag = false
                    break
                }
            }
            //如果为真,就停止死循环
            if flag {
                //判断标记的值
                break
            }
        }
        arr[i] = x
    }
    fmt.Println(arr)
}

func main() {
    makeArray()
}

1.给定一个路径名: pathName:="http://192.168.15.33/static/aa.jpeg" 获取文件名称:aa.jpeg

2.给定一个以下字符串:统计大写字母的个数,小写字母的个数,非字母的个数。

str:="aekjffjkJDJ294384848DKFJFJkdjfhfh2943845593nfnJRIEIFJ"

package main

import (
    "fmt"
    "strings"
)

/*
练习2:给定一个路径名:
pathName:="http://192.168.10.1:8080/Day33_Servlet/aa.jpeg"
获取文件名称:aa.jpeg

    给定一个以下字符串:统计大写字母的个数,小写字母的个数,非字母的个数。
str:="aekjffjkJDJ294384848DKFJFJkdjfhfh2943845593nfnJRIEIFJ"
*/

func main() {
    pathName := "http://192.168.10.1:8080/Day33_Servlet/aa.jpeg"
    //取出末尾元素方式一
    //slistStr:=strings.Split(pathName,"/")
    //fmt.Println(slistStr[len(slistStr)-1:])

    //方式二,找到/符号的索引,加一取出
    fileName := pathName[strings.LastIndex(pathName, "/")+1:]
    fmt.Printf("%T %v \n", fileName, fileName)

    //统计个数
    str:="aekjffjkJDJ294384848DKFJFJkdjfhfh2943845593nfnJRIEIFJ"
    count1 := 0
    count2 := 0
    count3 := 0

    for i := 0; i < len(str); i++ {
        if str[i] >= 'A' && str[i] <= 'Z' {
            count1++
        } else if str[i] >= 'a' && str[i] <= 'z' {
            count2++
        } else {
            count3++
        }
    }

    fmt.Printf("大写字母:%d,小写字母:%d,非字母:%d\n", count1, count2, count3)
}

1.练习:递归算法求5的阶乘

2.练习:兔子生兔子:fibonacci数列:第1,2两项数值都为1,从第3项开始,是前两项之和。使用递归算法,求第12项的数值。

func getfactorial(n int)int{
    if n== 1{
        return 1
    }
    return getfactorial(n-1) *n
}

1.一条协程打印100数字,另一条协程打印100字母

package main

import (
    "fmt"
    "time"
)

func printNum() {
    for i := 0; i < 100; i++ {
        fmt.Println("goroutine1 打印数字:", i)
        time.Sleep(1 * time.Second)

    }
}

func printChar() {
    for i := 0; i < 100; i++ {
        fmt.Printf("goroutine2 打印【字符】: %c\n", i)
        time.Sleep(1 * time.Second)
    }
}
func main() {
    //如果不加go协程去运行,函数会等待运行
    //加go 并发版运行,抢占式运行,每次结果都不一样
    //可以设置睡眠时间,查看go协程是并发运行
    go printChar()
    go printNum()
    time.Sleep(10 * time.Second)
    fmt.Println("main结束。。。")
}

1.创建并启动一个子 goroutine,打印100个数字,要保证在main goroutine结束前结束。(使用管道)

package main

import (
    "fmt"
    "time"
)

//利用chan阻塞的特性,延迟main进程结束
func printNum(ch1 chan bool) {
    for i := 1; i <= 100; i++ {
        fmt.Println(i)
        time.Sleep(10 * time.Millisecond)
    }
    ch1 <- true //写入一个标志位,true
}
func main() {
    //练习1:创建并启动一个子 goroutine,打印100个数字,要保证在main goroutine结束前结束。
    ch1 := make(chan bool)
    printNum(ch1)
    <-ch1 //读取管道数据,如果没读到数据,会一直阻塞,延迟main进程结束
}

1.通道channel的用法例题

package main

import (
    "fmt"
    "time"
)

func main() {
    //go的ok语法
    ch1 := make(chan int)
    go sendData(ch1)

    //channel关闭后不得再写入,可以读取
    //channel如果没关闭,且没有数据,再读取channel会pannic
    //读取数据
    for {
        time.Sleep(1*time.Second)//每秒读一次
        data,ok:=<-ch1//返回值data,与ok布尔值
        if !ok{
            fmt.Println("数据读取完毕,通道已经关闭",ok)
            break
        }
        fmt.Printf("已读取到数据【%d】%v\n",data,ok)
    }
}

func sendData(ch1 chan int) {
    for i := 1; i < 10; i++ {
        ch1 <- i //向通道写入数据
    }
    fmt.Println("数据写入完毕")
    close(ch1)//关闭管道,接收方已经无法取数据
}
posted @ 2019-06-26 15:32  AnthonyWang  阅读(192)  评论(0)    收藏  举报