The "Go" Learning Trip -- 2. Go Basics -- Part1-2

  基本数据类型和操作符

1. 文件名&关键字&标识符

  1) 所有go源码以.go结尾

  2) 标识符以字母下划线开头,大小写敏感,比如:

  3) _是特殊标识符,用来忽略结果

  4) 保留关键字

  

  

2. Go程序基本结构

 

  •   任何一个代码文件隶属于一个包
  •   import 关键字,引用其他包:

  • golang可执行程序,package main,并且有且只有一个main入口函数
  • 包中函数调用:
  1. 同一个包中函数,直接调用
  2. 不同包中函数,通过包名+点+函数名进行调用
  •   包访问控制规则:
  1. 大写意味着这个函数/变量是可导出的
  2. 小写意味着这个函数/变量是私有的,包外部不能访问

# exercise time -- exercise 1

    

 

 思路: 需要一个迭代,迭代的变量进行递减,并用格式化输出

# 代码如下

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func calcValue(n int) {
 8     for item := 0; item <= n; item++ {
 9         fmt.Printf("%d + %d = %d\n", item, n-item, n)
10     }
11 }
12 func main() {
13     calcValue(10)
14 }
View Code

 

# exercise time -- exercise 2

 

# 比较简单直接上码

 1 //  新建一个main目录下的mainDemo.go
 2 package main
 3 
 4 import (
 5     "fmt"
 6     "go_dev/day2/example1/add"
 7 )
 8 
 9 func main() {
10     fmt.Println(add.Name)
11     fmt.Println(add.Age)  //这里注意如果用小写的变量名,将提示不可引用
12 }
13 
14 // 新建一个add目录下的addPkg.go
15 package add
16 
17 // Name is Author
18 var Name = "Loki"
19 
20 // Age is Author's age
21 var Age = 16
View Code

 

# exercise time -- exercise 3

 

# 比较简单 X 2 直接上码

 1 // 新建目录main下面的mainDemo.go
 2 package main
 3 
 4 import (
 5     "fmt"
 6     lokiPkg "go_dev/day2/example3/add" // 这里定义别名
 7 )
 8 
 9 func main() {
10     fmt.Println("result: ", lokiPkg.Name) //这里调用别名
11     fmt.Println("result: ", lokiPkg.Age)
12 }
13 
14 // 新建目录add下面的addDemo.go
15 package add
16 
17 var Name string = "Loki"
18 var Age int = 16
View Code

 

# exercise time -- exercise 4

 

 

 # 关于 init() 函数 会优先执行

执行顺序:  先初始化全局变量 --> 调用初始化函数init() -->  执行main()函数

 1 //main目录下的mainDemo.go
 2 package main
 3 
 4 import (
 5     "fmt"                      //lokiPkg "go_dev/day2/example3/add" // 这里定义别名
 6     "go_dev/day2/example3/add" // 这里定义别名
 7 )
 8 
 9 func main() {
10     fmt.Println("result: ", add.Name) //这里调用别名
11     fmt.Println("result: ", add.Age)
12 }
13 
14 
15 //add目录下的addDemo.go
16 package add
17 
18 import (
19     "fmt"
20 )
21 
22 // Name just Master's name
23 var Name string = "Loki"
24 
25 // Age just Master's age
26 var Age int = 16
27 
28 // init code will execute first
29 func init() { //Note! here "init" is lower case
30     fmt.Println("Welcome back! Master")
31 
32 }
View Code

 # exercise time -- exercise 5

 

 

# 包的初始化,不引用。  如果仅仅是想导入包,但是不小调用包的内容可以在包名前面加一个"_"

PS:多层导入,会以最里面(最深入的一层)的导入的init() 函数开始执行

 1 package main
 2 
 3 import (
 4     _ "go_dev/day2/example3/add" // 注意这里,导入了包,包名位置有个"_"
 5 )
 6 
 7 func main() {
 8     // fmt.Println("result: ", add.Name) //这里取消了调用
 9     // fmt.Println("result: ", add.Age)
10 }
View Code

 

函数声明和注释

1. 函数声明:

格式:  func 函数名字(参数列表)(返回值列表){}

  

 

无返回值

有参数,有返回值

有参数,有多个返回值

 

 

 2. 注释,两种注释,单行注释: //  和多行注释/* */

 

 

 

 

 3. 常量和变量

  •   常量使用const 修饰, 代表永远是只读的,不能修改。
  •   const 只能修饰boolean number(int相关类型、浮点型、complex)和string
  •   语法: const identifier  [TYPE] = value,其中type可以省去

 

 

 

 # exercise time -- exercise 6

 

 

 

# 常量实验

毫秒: Millisecond

微秒: Microsecond 

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 const (
 9     Male   = 1
10     Female = 2
11 )
12 
13 func main() {
14     for {
15         if sec := time.Now().Unix(); sec%Female == 0 {
16             fmt.Print("Female")
17         } else {
18             fmt.Println("Man")
19         }
20         time.Sleep(time.Second)  //防止死循环执行太快耗尽CPU
21     }
22 }
View Code

 

 # iota

iota是golang语言的常量计数器,只能在常量的表达式中使用。iota在const关键字出现时将被重置为0(const内部的第一行之前),const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。使用iota能简化定义,在定义枚举时很有用。

 # 写个例子

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     const (
 9         _ = iota // 丢弃第一个数字"0"
10         a
11         b
12         c
13     )
14     fmt.Println(a, b, c)
15 
16 }
View Code

 

# 变量

语法: var identifier type

 

 

 

 

PS: GO语言里面可以做类型推导 

 # exercise time -- exercise 7 

 

 

 Tips: 相当于是个获取CMD设置的%变量名% 的东东(os.Getenv)

# 所以,可以这样玩,举个例子

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "os"
 6 )
 7 
 8 func main() {
 9         // 变量的常规写法
10     var goos string = os.Getenv("OS")
11         // 变量的偷懒写法,Getenv里面的值就是cmd里面的%变量%
12     path := os.Getenv("PATH")
13     goPath := os.Getenv("GOPATH")
14     goRoot := os.Getenv("GOROOT")
15     fmt.Printf("The OS is : %s\n", goos)
16     fmt.Printf("The GO Path is : %s\n", goPath)
17     fmt.Printf("The GO Root is : %s\n", goRoot)
18     fmt.Printf("The OS Path is : %s\n", path)
19 
20 }
View Code

 

 

 值类型和引用类型

 

32位系统指针是4个字节

64位系统指针是8个字节

 

值类型:基本数据类型int 、float、bool、string以及数组和struct(结构体).

引用类型:指针、slice(切片)、map、chan等都是引用类型

  # exercise time -- exercise 8 

 

 

 

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     a := 100                           //值类型
 9     // 可以简写为 b := make(chain int,1)
10     var b chan int = make(chan int, 1) //引用类型
11     fmt.Println("a=", a)
12     fmt.Println("b=", b)
13 
14 }
View Code

 

# 输出结果截图

 

# 附加演示有“游标”和无游标对函数调用以后对变量的影响

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 // Noncursor is 非定义游标的方式
 8 func Noncursor(n int) {
 9     n = 10
10 }
11 
12 // Cursor is 定义使用游标的方式
13 func Cursor(n1 *int) {
14     *n1 = 11
15 }
16 
17 func main() {
18     n := 99
19     n1 := 99
20     a := 100                           //值类型
21     var b chan int = make(chan int, 1) //引用类型
22     fmt.Println("a=", a)
23     fmt.Println("b=", b)
24     Noncursor(n)
25     fmt.Println("n=", n) // 结果还是为99 没有变化
26     Cursor(&n1)
27     fmt.Println("n1=", n1) //结果为11 已经修改
28 
29 }
View Code

 PS: 堆 & 栈的区别

栈 先进后出    占空间去分配                   <--- 值类型

堆 先进先出     系统的内存堆分配           <---  引用类型

 栈大小 C语言 几m    Go语言几k

堆内存性能没有栈内存高

 

  # exercise time -- exercise 9 

 

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 // ChangeWay1 is change x and y value
 8 func ChangeWay1(x, y int) (int, int) {
 9     fmt.Println("Myself Way1---↓ Success")
10     x1, y1 := y, x
11     return x1, y1
12 }
13 
14 // ChangeWay2 is change x and y value, --> Error Demo!!! <--
15 func ChangeWay2(x, y int) {
16     fmt.Println("Error Way2---↓ Fail")
17     tmp := x
18     x = y
19     y = tmp
20     return
21 }
22 
23 // ChangeWay3 is change x and y value, 采用了修改游标方式,直接修改了地址
24 func ChangeWay3(x, y *int) {
25     fmt.Println("Right Way3---↓ Sucess")
26     tmp := *x
27     *x = *y
28     *y = tmp
29     return
30 }
31 
32 // ChangeWay4 is change x and y value
33 func ChangeWay4(x, y int) (int, int) {
34     fmt.Println("Myself Way4---↓ Success")
35     return y, x
36 }
37 
38 func main() {
39     x := 3
40     y := 4
41     fmt.Println(ChangeWay1(x, y))
42     ChangeWay2(5, 6)
43     fmt.Println(x, y)
44     fmt.Println(ChangeWay4(x, y)) // 注意这里方法3之所以要放到方法4下面,是因为方法3修改了地址指向内容,会导致地址指向的值产生变化
45     x, y = y, x  // 这里值已经被修改
46     fmt.Println("Myself Way5---↓ Success", x, y)
47     ChangeWay3(&x, &y)
48     fmt.Println(x, y)  // 这里再次做了一个交换,所以值又变了回去
49 
50 }
View Code

# 执行结果

 

 变量的作用域

1. 在函数内部声明的变量叫做局部变量,声明周期仅限于函数内部。

2. 在函数外部声明的变量叫做全局变量,生命周期作用于整个包,如果是大写的,则作用于整个程序(小写也是作用于整个程序,只是私有,外部访问不了)

3. 在函数内部语句块声明的变量仅在语句块中生效,语句块外不起作用

# 语句块 是被"{ }"里面的语句,例如:

func test(){    //局部变量

    for i :=0; i < 100; i++{   //语句块

    var b = i * 2      

    }

}

 

   # exercise time -- exercise 10

 

 

 # 测试结果

 

    # exercise time -- exercise 11

 

 

  # 测试结果

 

 

 

    # exercise time -- exercise 12

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 var a string
 8 
 9 func main() {
10     a = "G"
11     print(a)
12     f1()
13 
14 }
15 
16 func f1() {
17     a := "O"
18     fmt.Println(a)
19     f2()
20 }
21 
22 func f2() {
23     fmt.Println(a)
24 }
View Code

# 执行结果

 

  

4. 数据类型和操作符

bool类型,只能存true和false

 

  2)相关操作符, !、&&、||

&&特性--> 短路操作: 前面表达式如果false,就不会去求后面的表达式

|| 特性 --> 前面表达式已经为true,后面的表达式就不用求了

 

关于这3个符号的优先级:  !>&&>||.

# 逻辑与(&&) (有假即假

 

 # 逻辑或(||)(有真即真

 

 # 举个例子

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     var a bool = true
 9     var b bool = false
10     // "&&" 有假即假, "||"有真即真
11     fmt.Printf(" !a的结果: %t\n !b的结果: %t\n a && b的结果: %t\n a||b的结果: %t\n", !a, !b, a && b, a || b)
12 
13 }
View Code

# 执行结果截图

 

 

数字类型,主要有int、int8、int16、int32、int64、uint8、uint16、uint32、uint64、float32、float64

 PS: uint = 无符号整型; 有符号和无符号的区别(+、- 正负)

8位(1字节)

 

类型转换,type(variable),比如:var a int=8; var b int32=int32(a)

     # exercise time -- exercise 13

 

 

 

 # 上面输出结果肯定是编译错误,原因见下面代码:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     var n int16 = 34
 9     var m int32
10     // m = n   这里没有使用类型转换,编译将报错
11     m = int32(n) // 这里使用了类型转换,可以正常输出结果
12     fmt.Printf("m is %d\n n is %d\n", m, n)
13 
14 }
View Code

 

逻辑操作符: == 、!=、<、<=、>和>=

数学操作符:+、-、*、/等等

PS: 一个等于符号"=" 是赋值

 

 

    # exercise time -- exercise 14

 

 

 # 10 个显示结果不方便看,改为了3

# 里面有个 math/rand 的包,有点意思

# db.Seed(time.Now().UnixNano()) // 初始化随机种子以纳秒方式产生随机(不设置这个将产生重复值)
 1 package main
 2 
 3 import (
 4     "fmt"
 5     db "math/rand"  //设置别名
 6     "time"
 7 )
 8 
 9 // 初始化工作
10 func init() {
11     db.Seed(time.Now().UnixNano()) // 让随机种子以纳秒方式产生随机(不设置这个将产生重复值)
12 
13 }
14 
15 func main() {
16     // 10个随机整数
17     for item := 0; item < 3; item++ {
18         res := db.Int()
19         fmt.Println(res)
20     }
21     // 10 个小于100的随机整数
22     for item := 0; item < 3; item++ {
23         res := db.Intn(100)
24         fmt.Println(res)
25     }
26     // 10 个随机浮点数
27     for item := 0; item < 3; item++ {
28         res := db.Float32()
29         fmt.Println(res)
30     }
31 
32 }
View Code

  

5. 字符串类型

字符类型: var a byte

                    var a byte = `c`  (只能使用单引号)

字符串类型:  var str string

 

字符串表示两种方式: 1)双引号 2)`` (反引号

双引号:

反引号:源生字符串

 

 

 # 双引号和反引号

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     name := "Loki"
 9     // 会保留换行操作动作,字符串原本的格式,换行不需要转义符
10     var str = `Hello Loki\n \n \n 
11     this is a test string,
12     This is a test string too.`
13     fmt.Printf("Hello %s \n\n", name) // "" 双引号需要转义符
14     fmt.Printf(`str2= %s`, str)
15 }
View Code

 

#  关于byte和单引号不得不说的故事

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     name := "Loki"
 9     luckyLetter := 'L' // 用单引号表示定义一个byte字符
10     fmt.Printf("My name is %s\n", name)
11     fmt.Println(luckyLetter)                         // 发现输出字符是数字?其实是ASCII编码
12     fmt.Printf("This is letter ->%c<-", luckyLetter) // %c 表示byte,使用格式化输出即可显示正确字母
13 }
View Code

 

# 详细的官方文档参考

https://go-zh.org/pkg/fmt/

 

# 从int 转换为str 例子:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     var data int = 100
 9     fmt.Println("value:", data)
10     fmt.Printf("数据类型是:%T\n", data)
11     str := fmt.Sprintf("%d", data) // int to str
12     fmt.Println("value: ", str)
13     fmt.Printf("数据额类型是:%T\n", str)
14     fmt.Printf("a=%q", str )
15 
16 }
View Code

 

# 2种字符串拼接方法

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     str1 := "Loki"
 9     str2 := 16
10     str3 := fmt.Sprintf("%d", str2)
11 
12     way1 := str1 + " " + str3                //  string joint way 1
13     way2 := fmt.Sprintf("%s %s", str1, str3) // string joint way 2
14     fmt.Println(way1)
15     fmt.Println(way2)
16 
17 }
View Code

 

# 字符串长度判断len()和切片

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     str1 := "Loki So Cool!"
 9     fmt.Println("string length is : ", len(str1))
10     fmt.Println(str1[0:3])
11     fmt.Println(str1[5:7])
12     fmt.Println(str1[8:])
13 
14 }
View Code

 

# 2种方法实现字符串反转功能函数 

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 // reverse is function help string reversal
 8 func reverse(str string) string {
 9     var res string
10     strLen := len(str)
11     for i := 0; i < strLen; i++ {
12         res = res + fmt.Sprintf("%c", str[strLen-i-1])
13     }
14     return res
15 }
16 
17 func array(str string) string {
18     var res []byte    //定义数组
19     tmp := []byte(str)
20     strLen := len(str)
21     for i := 0; i < strLen; i++ {
22         res = append(res, tmp[strLen-i-1])  // 从末尾到开头一个个字符加入数组
23     }
24     // fmt.Println(res)  输出结果默认是数组,所以返回值需要string()一下
25     return string(res)
26 }
27 
28 func main() {
29     str1 := "Loki So Cool!"
30     result := reverse(str1)
31     fmt.Println("way1 result: ", result)
32     resultWay2 := array(str1)
33     fmt.Println("war2 result: ", resultWay2)
34 }
View Code

 

 

 做题思路:

1. 搞清楚几个陌生术语,然后进行此题逻辑思考

素数: 只能被1整和自己整除的数,我们就认为它是素数

%  运算符 - 模除(取整除后的余数) 

# 方法1

 1 package main
 2 
 3 import "fmt"
 4 
 5 //  1. 判断 101-200 之间有多少个素数,并输出所有素数。
 6 func isPrime(num int) bool {
 7     if num <= 1 {
 8         return false
 9     }
10     for i := 2; i < num; i++ {
11         if num%i == 0 {
12             return false
13         }
14     }
15     return true
16 }
17 
18 func main() {
19     count := 0
20     for x := 101; x < 200; x++ {
21         res := isPrime(x)
22         if res {
23             fmt.Printf("%d is Prime\n", x)
24             count++
25         }
26     }
27     fmt.Printf("Total is %d", count)
28 
29 }
View Code

  

“水仙花数”  解题思路,分别把输入的个位(%10)、十位(除以10,再%10)、百位(除以100,再%10)取出,分别再进行个位,十位,百位只积(各自数3次方之积),最后进行相加的结果等于数本身。

# 方法1

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "math"
 6 )
 7 
 8 func isNarcissistc(n int) bool {
 9     var i, j, k int
10     i = (n % 10)
11     j = (n / 10) % 10
12     k = (n / 100) % 10
13     sum := i*i*i + j*j*j + k*k*k  // 次方可以使用math.Pow(x,y) x = 值 , y = 次方
14     // fmt.Println(math.Pow(float64(i), 3), math.Pow(float64(j), 3), math.Pow(float64(k), 3))
15     return sum == n
16 }
17 
18 func main() {
19     var startValue int
20     var endValue int
21     fmt.Scanf("%d%d", &startValue, &endValue)
22     for i := startValue; i < endValue; i++ {
23         if isNarcissistc(i) == true {
24             fmt.Println(i, "is Narcissistc Number")
25         }
26     }
27 }
View Code

# 方法2 采用了默认是字符,用字符ASCII编码转换后再计算的方法得到结果,再进行对比

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "strconv"  // 用于字符串转换int的包
 6 )
 7 
 8 func main() {
 9     var str string
10     // fmt.Scanf("%s", &str)
11     str = "153"
12 
13     var result = 0
14     for i := 0; i < len(str); i++ {
15         num := int(str[i] - '0')  // ASCII 码  数字对应编码减去ASCII 数字0(十进制ASCII:48)都等于原来数本身, 这里字符'1' '5' '3'(ASCII:49 53 51);这里为了计算把str转换成了int
16         result += (num * num * num)
17     }
18 
19     number, err := strconv.Atoi(str)  //把字符串"153" 转换为数字153
20     if err != nil {
21         fmt.Printf("can not convert %s to int\n", str)
22         return
23     }
24     if result == number {                   // 对比 字符串转换的数字和计算结果的数字
25         fmt.Printf("%d is narcissistic number.√", number)
26     } else {
27         fmt.Printf("%d is not narcissistic number.×", number)
28     }
29 }
View Code

# 方法3 自己突发奇想的版本,主要借用了 strconv.Atoi(str) 功能

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "strconv"
 6 )
 7 
 8 func wordToint(str string) int {
 9     num, err := strconv.Atoi(str)
10     if err != nil {
11         fmt.Printf("can not convert %s to int\n", string(str))
12     }
13     return num
14 }
15 
16 func main() {
17     var str string
18     var result = 0
19     str = "154"
20     for i := 0; i < len(str); i++ {
21         num := wordToint(string(str[i]))
22         result += (num * num * num)
23     }
24     number := wordToint(str)
25     if result == number {
26         fmt.Printf("%d is narcissistic number.", number)
27     } else {
28         fmt.Printf("%d is not narcissistic number.", number)
29     }
30 }
View Code

 

阶乘(factorial) 解题思路,搞清楚什么是“阶乘” ,下面几个定义:

阶乘是基斯顿·卡曼(Christian Kramp,1760~1826)于 1808 年发明的运算符号,是数学术语。

一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。

0! = 1 

n! = 1 x 2 x 3 x ... x(n - 1)n

# 方法一(使用递归)

 1 package main
 2 
 3 import "fmt"
 4 
 5 func factorial(n int) int {
 6     if n <= 1 {
 7         return 1
 8     }
 9     return factorial(n-1) * n
10 }
11 
12 func main() {
13     // fmt.Println(factorial(5))
14     var n int
15     countSum := 0       // 计算并记录阶乘之和
16     fmt.Scanf("%d", &n) // 用户输入的n值,并改变函数内的值用 "&" 符号
17     for i := 1; i <= n; i++ {
18         countSum = countSum + factorial(i)
19     }
20     fmt.Println("factorial value sum is : ", countSum)
21 }
View Code

# 方法二(使用循环)

 1 package main
 2 
 3 import "fmt"
 4 
 5 func factorial(n int) int {
 6     var sum int = 0        // 用于最后的求和结果
 7     var lastValues int = 1 // 用于记录上一次的乘积
 8 
 9     if n <= 1 { // 排除用户输入0和1 让0! 和 1! 直接返回结果
10         return 1
11     }
12 
13     for i := 1; i <= n; i++ {
14         lastValues = lastValues * i
15         fmt.Printf("%d!=%v\n", i, lastValues)
16         sum += lastValues
17     }
18     return sum
19 }
View Code

# 执行结果截图

 

posted @ 2020-12-01 08:07  Cong0ks  阅读(93)  评论(0编辑  收藏  举报