Go语言学习之3 流程控制、函数

主要内容:

1. strings和strconv使用
2. Go中的时间和日期类型
3. 指针类型
4. 流程控制
5. 函数详解

1. strings和strconv使用

//strings
1. strings.HasPrefix(s string, prefix string) bool:判断字符串s是否以prefix开头 。
2. strings.HasSuffix(s string, suffix string) bool:判断字符串s是否以suffix结尾。
3. strings.Index(s string, str string) int:判断str在s中首次出现的位置,如果没有
4. strings.LastIndex(s string, str string) int:判断str在s中最后出现的位置,如果没有
5. strings.Replace(str string, old string, new string, n int)string:字符串替换
6. strings.Count(str string, substr string)int:字符串计数
7. strings.Repeat(str string, count int)string:重复count次str
8. strings.ToLower(str string)string:转为小写
9. strings.ToUpper(str string)string:转为大写
10. strings.TrimSpace(str string) string:去掉字符串首尾空白字符strings.Trim(str string, cut string) string:去掉字符串首尾cut字符strings.TrimLeft(str string, cut string) string:去掉字符串首cut字符strings.TrimRight(str string, cut string) string:去掉字符串首cut字符
11. strings.Fields(str string) []string:返回str空格分隔的所有子串的slicestrings.Split(str string, split string) []string:返回str split分隔的所有子串的slice
12. strings.Join(s1 []string, sep string) string:用sep把s1中的所有元素链接起来//strconv
13. strconv.Itoa(i int) string:把一个整数i转成字符串
14. strconv.Atoi(str string)(int, error):把一个字符串转成整数

例子:

  1 package main 
  2 
  3 import (
  4     "fmt"
  5     "strings"
  6     "strconv"
  7 )
  8 
  9 func main() {
 10     var res bool
 11     //HasPrefix
 12     res = strings.HasPrefix("https://www.baidu.com", "https://") //true
 13     fmt.Printf("%v\n", res)
 14     res = strings.HasPrefix("https://www.baidu.com", "albaba") //false
 15     fmt.Printf("%v\n", res)
 16 
 17     //HasSuffix
 18     res = strings.HasSuffix("/root/temp/", "/") //true
 19     fmt.Printf("%v\n", res)
 20     res = strings.HasSuffix("/root/temp/", "=") //false
 21     fmt.Printf("%v\n", res)
 22 
 23     var result int
 24     //Index
 25     result = strings.Index("hahahelloworld", "he") //4
 26     fmt.Printf("%v\n", result)
 27     
 28     //LastIndex
 29     result = strings.LastIndex("hahahelloworldhe", "he") //14
 30     fmt.Printf("%v\n", result)
 31 
 32     var result2 string
 33     //Replace
 34     result2 = strings.Replace("hahahelloworldhe", "ha", "HA", 1) //HAhahelloworldhe
 35     fmt.Printf("%v\n", result2)
 36     result2 = strings.Replace("hahahelloworldhe", "ha", "HA", -1) //HAHAhelloworldhe
 37     fmt.Printf("%v\n", result2)
 38 
 39     //Count
 40     result = strings.Count("hahahelloworldhe", "ha") //2
 41     fmt.Printf("%v\n", result)
 42 
 43     //Repeat
 44     result2 = strings.Repeat("ha", 3) //hahaha
 45     fmt.Printf("%v\n", result2)
 46     
 47     //ToLower
 48     result2 = strings.ToLower("heLLo") //hello
 49     fmt.Printf("%v\n", result2)
 50 
 51     //ToUpper
 52     result2 = strings.ToUpper("hello") //HELLO
 53     fmt.Printf("%v\n", result2)
 54 
 55     //TrimSpace
 56     result2 = strings.TrimSpace("   hello   ") //hello
 57     fmt.Printf("%v\n", result2)
 58 
 59     //Trim
 60     result2 = strings.Trim("123hello123", "123") //hello
 61     fmt.Printf("%v\n", result2)
 62 
 63     //TrimLeft
 64     result2 = strings.TrimLeft("123hello123", "123") //hello123
 65     fmt.Printf("%v\n", result2)
 66 
 67     //TrimRight
 68     result2 = strings.TrimRight("123hello123", "123") //123hello
 69     fmt.Printf("%v\n", result2)
 70 
 71     var result3 []string
 72     //Fields
 73     result3 = strings.Fields("root temp work")
 74     for i := 0; i < len(result3); i++ {
 75         fmt.Printf("%v\n", result3[i])
 76     }
 77     
 78     //Split
 79     result3 = strings.Split("/root/temp/work", "/")
 80     for i := 0; i < len(result3); i++ {
 81         fmt.Printf("%v\n", result3[i])
 82     }
 83 
 84     //Join
 85     result3 = [] string{"root", "temp", "work"}
 86     result2 = strings.Join(result3, "/") // root/temp/work
 87     fmt.Println(result2)
 88 
 89     //Itoa
 90     num := 123
 91     result2 = strconv.Itoa(num) // root/temp/work
 92     fmt.Printf("%s\n", result2) // 123
 93 
 94     //Atoi
 95     str := "12345"
 96     number, err := strconv.Atoi(str) // root/temp/work
 97     if err != nil {
 98         fmt.Printf("Can not convert %s to int\n", str)
 99         return
100     }
101     fmt.Printf("%d\n", number) // 12345
102 }
example

练习1:判断一个url是否以http://开头,如果不是,则加上http://。
练习2:判断一个路径是否以"/"结尾,如果不是,则加上/。

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "strings"
 6 )
 7 
 8 func urlProcess(url string) string {
 9     res := strings.HasPrefix(url, "http://")
10     if !res {
11         url = fmt.Sprintf("http://%s", url)
12     }
13     return url
14 }
15 
16 func pathProcess(path string) string {
17     res := strings.HasSuffix(path, "/")
18     if !res {
19         path = fmt.Sprintf("%s/", path)
20     }
21     return path
22 }
23 
24 func main() {
25     var (
26         url string
27         path string        
28     )
29 
30     fmt.Println("Input url and path >>")
31     fmt.Scanf("%s%s", &url, &path)
32 
33     url = urlProcess(url)
34     path = pathProcess(path)
35 
36     fmt.Println("url: ", url)
37     fmt.Println("path: ", path)
38 }
练习1和2

练习3:写一个函数返回一个字符串在另一个字符串的首次出现和最后出现位置。

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "strings"
 6 )
 7 
 8 func strIndex(str string, substr string)(int, int) {
 9     var startIndex, endIndex int
10 
11     startIndex = strings.Index(str, substr)
12     endIndex = strings.LastIndex(str, substr)
13 
14     return startIndex, endIndex
15 }
16 
17 func main() {
18     var str, substr string
19     fmt.Println("Input a string >> ")
20     fmt.Scanf("%s%s", &str, &substr)
21 
22     start, end := strIndex(str, substr)
23     if start < 0 {
24         fmt.Printf("Can not find %s in %s.\n", substr, str)
25     } else {
26         fmt.Printf("First find %s in %s %d index.\n", substr, str, start)
27     }
28 
29     if end < 0 {
30         fmt.Printf("Can not find %s in %s.\n", substr, str)
31     } else {
32         fmt.Printf("Last find %s in %s %d index.\n", substr, str, end)
33     }
34 }
练习3

练习4:写一个函数分别演示Replace、Count、Repeat、ToLower、ToUpper的用法。
练习5:写一个函数分别演示TrimSpace、Trim、TrimLeft、TrimRight、Field、Split、以及Join的用法。
练习6:写一个函数分别演示Itoa、Atoi的用法。

2. Go中的时间和日期类型

1. time包
2. time.Time类型,用来表示时间
3. 获取当前时间, now := time.Now()
4. time.Now().Day(),time.Now().Minute(),time.Now().Month(),time.Now().Year()
5. 格式化,fmt.Printf("%02d/%02d%02d %02d:%02d:%02d", now.Year()…)
6. time.Duration用来表示纳秒
7. 一些常量:
    const (
         Nanosecond Duration = 1
         Microsecond = 1000 * Nanosecond
         Millisecond = 1000 * Microsecond
         Second = 1000 * Millisecond
         Minute = 60 * Second
         Hour = 60 * Minute
    )
8. 格式化:
    now := time.Now()
    fmt.Println(now.Format(“02/1/2006 15:04”))
    fmt.Println(now.Format(“2006/1/02 15:04”))
    fmt.Println(now.Format(“2006/1/02”))

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

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 func main() {
 9     now := time.Now()
10     fmt.Println(now.Format("02/1/2006 15:04")) // 12/2/2019 18:13
11     fmt.Println(now.Format("2006/1/02 15:04")) // 2019/2/12 18:13
12     fmt.Println(now.Format("2006/1/02")) // 2019/2/12
13 }
练习6

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

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 func costTime() {
 9     for i := 0; i < 100000000; i++ {
10 
11     }
12 }
13 
14 func main() {
15     start := time.Now().UnixNano() // ns
16     costTime()
17     end := time.Now().UnixNano()
18 
19     fmt.Printf("cost:%d us\n", (end-start)/1000)
20 }
练习7

3. 指针类型

1. 普通类型,变量存的就是值,也叫值类型
2. 获取变量的地址,用&,比如: var a int, 获取a的地址:&a
3. 指针类型,变量存的是一个地址,这个地址存的才是值
4. 获取指针类型所指向的值,使用:*,比如:var *p int, 使用*p获取p指向的值

练习8:写一个程序,获取一个变量的地址,并打印到终端。
练习9:写一个函数,传入一个int类型的指针,并在函数中修改所指向的值。在main函数中调用这个函数,并把修改前后的值打印到终端,观察结果。

 1 package main 
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func test(num int) {
 8     fmt.Printf("In the test add %v\n", &num)
 9 }
10 
11 func changeNum(num *int) {
12     *num = 100
13 }
14 
15 func main() {
16     var num int = 10
17     fmt.Printf("In the main add %v\n", &num) //In the main add 0xc04203c1d0
18     test(num) // In the test add 0xc04203c1d8
19     fmt.Printf("num = %d\n", num)  // num = 10
20     changeNum(&num)
21     fmt.Printf("num = %d\n", num) //num = 100
22 }
练习8和9

4. 流程控制

1. If / else分支判断

单个分支

if condition1 {
}

两个分支

if condition1 {    
} else {
}

多个分支

if condition1 {
} else if condition2 {
} else if condition3 {
} else {
}

注意:下面这种写法是错误的

if condition1 {
}
else {
}

练习10:写一个程序,从终端读取输入,并转成整数,如果转成整数出错,则输出 "can not convert to int",并返回。否则输出该整数。

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "strconv"
 6 )
 7 
 8 func main() {
 9     var str string
10     fmt.Println("Input a number >>")
11     fmt.Scanf("%s", &str)
12     number, err := strconv.Atoi(str)
13     if err != nil {
14         fmt.Printf("Can not convert %s to int\n", str)
15         return
16     }
17     fmt.Printf("%d", number)
18 }
练习10

2. switch case语句
语法:
       switch var {
           case var1:
           case var2:
           case var3:
           default:
       }

特别注意:go语言中和C语言不一样,在case后面没有break语句。

 1 switch var {
 2            case var1:
 3                 {
 4                     语句
 5                     break;
 6                 }
 7                 
 8            case var2:
 9                 {
10                     语句
11                     break;
12                 }
13            case var3:
14                 {
15                     语句
16                     break;
17                 }
18            default:
19                     语句
20        }
C语言写法

写法1:

var num int = 2
switch num {case 0:fmt.Println("0")case 1:fmt.Println("1")case 2:fmt.Println("2")default:fmt.Printf("%d\n", num)
}

写法2:跨越case的fallthrough

var i = 0
switch i {
case 0:fmt.Println("0") // 会执行
    fallthrough
case 1:fmt.Println("1") // 由于上面fallthrough 所以会执行
case 2:fmt.Println("2")
default:fmt.Println("default")
}

注意:加上fallthrough则当前case语句执行完成之后会紧接着执行相邻的第一条case。

写法3:

var i = 0
switch i {//两个case合并case 0, 1:fmt.Println("0 or 1")case 2:fmt.Println("2")default:fmt.Println("def")
}

写法4:

var i = 0
switch {case i > 0 && i < 10:fmt.Println("i > 0 and i < 10")case i >= 10 && i < 20:fmt.Println("i > 10 and i < 20")default:fmt.Println("default")
}

写法5:

switch i := 15; {case i > 0 && i < 10:fmt.Println("i > 0 and i < 10")case i >= 10 && i < 20:fmt.Println("i > 10 and i < 20")default:fmt.Println("def")
}

注意: i := 15; 后面的分号(;)

 练习11:猜数字,写一个程序,随机生成一个0到100的整数n,然后用户在终端,输入数字,如果和n相等,则提示用户猜对了。如果不相等,则提示用户,大于或小于n。

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "math/rand"
 6 )
 7 
 8 func main() {
 9     var n int
10     n = rand.Intn(100)
11 
12     for {
13         var input int
14         fmt.Println("Input your guess >> ")
15         //注意后面的\n作用,如果没有的话,则输入的数和
16         fmt.Scanf("%d\n", &input)
17         flag := false
18         switch {
19         case input == n:
20             fmt.Println("you are right")
21             flag = true
22         case input > n:
23             fmt.Println("bigger")
24         case input < n:
25             fmt.Println("less")
26         }
27 
28         if flag {
29             break
30         }
31     }
32 }
练习11

3. for 语句

写法1:

for 初始化语句; 条件判断; 变量修改 {
}
//例如
for i := 0; i < 100; i++ {fmt.Printf("i=%d\n", i)
}

练习12:写一个程序,在终端打印如下图形。

A
AA
AAA
AAAA
AAAAA
 1 package main 
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     var row int
 9     fmt.Println("Input row number >>")
10     fmt.Scanf("%d", &row)
11     for i := 0; i < row; i++ {
12         for j := 0; j <= i; j++ {
13             fmt.Printf("A")
14         }
15         fmt.Println()
16     }
17 }
练习12

写法2:

for  条件 {
}

例如:下面三个条件为真都是死循环

for i > 0 {fmt.Println("i > 0")
}for true {fmt.Println("i > 0")
}for {fmt.Println("i > 0")
}

4. for range 语句

写法3:用来遍历数组、slice、map、chan

str := "hello world,中国" //汉字占3个字节for i, v := range str {fmt.Printf("index = %d val = %c byteLen = %d\n", i, v, len([] byte(string(v))))}

5. break、continue语句

package mainimport "fmt"func main() {str := "hello world,中国"for i, v := range str {if i > 2 {continue}if (i > 3) {break  }fmt.Printf("index[%d] val[%c] len[%d]\n", i, v, len([]byte(string(v))))}
}//输出:
//index[0] val[h] len[1]
//index[1] val[e] len[1]
//index[2] val[l] len[1]

break 语句可以结束 for、switch 和 select 的代码块。break 语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的 for、switch 和 select 的代码块上。例如:

package main
import "fmt"
func main() {
OuterLoop:for i := 0; i < 2; i++ {for j := 0; j < 5; j++ {switch j {case 2:fmt.Println(i, j)break OuterLoopcase 3:fmt.Println(i, j)break OuterLoop}}}
}//输出 说明第10行的break OuterLoop直接跳出外层循环
//0 2

continue 语句可以结束当前循环,开始下一次的循环迭代过程,仅限在 for 循环内使用。在 continue 语句后添加标签时,表示开始标签对应的循环。例如:

package main
import "fmt"
func main() {
OuterLoop: //代码说明:第 10 行将结束当前循环,开启下一次的外层循环,而不是第 10 行的内循环。for i := 0; i < 2; i++ {for j := 0; j < 5; j++ {switch j {case 2:fmt.Println(i, j)continue OuterLoop}}}
}//输出:
//0 2
//1 2

6. goto 和 label 语句

goto 语句通过标签进行代码间的无条件跳转。goto 语句可以在快速跳出循环、避免重复退出上有一定的帮助。Go 语言中使用 goto 语句能简化一些代码的实现过程。

package mainfunc main() {i := 0
HERE:print(i)i++if i == 5 {return}goto HERE
}//输出:
//01234

 5. 函数

1. 声明语法:func 函数名 (参数列表) [(返回值列表)] {}

//无参数,无返回值
func add() {
}//有参数,无返回值
func add(a int, b int) {
}//有参数,一个返回值
func add(a int, b int) int {
}//有参数,两个返回值
func add(a int, b int) (int, int) {
}//有参数,两个返回值
func add(a, b int) (int, int) {
}

2. golang函数特点:
    a. 不支持重载,一个包不能有两个名字一样的函数
    b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量

 1 package main
 2 
 3 import "fmt"
 4 
 5 func add(a, b int) int {
 6     return a + b
 7 }
 8 
 9 func main() {
10     c := add  //将函数add的地址赋值给变量c
11     fmt.Println(c) //0x4888e0
12 
13     sum := c(10, 20)
14     fmt.Println(sum)
15     // if (c == add) {  //invalid operation: c == add (func can only be compared to nil)
16     //     fmt.Println("c equal add")
17     // }
18 }
函数赋值给变量

    c. 匿名函数

 1 package main
 2 
 3 import "fmt"
 4 
 5 var (
 6     //add存放的是匿名函数的地址
 7     add = func(a int, b int) int {
 8         return a + b
 9     }
10     
11     //sub_res存放的是匿名函数执行的结果100
12     sub_res = func(a int, b int) int {
13         return a - b
14     }(200, 100) 
15 )
16 
17 func test(a, b int) int {
18     //mult存放的是匿名函数的地址
19     mult := func(m int, n int) int {
20         return m*n
21     }
22     return mult(a, b)
23 }
24 
25 func main() {
26     fmt.Println(add(100, 200))  //300
27     fmt.Println(sub_res)  //100
28         fmt.Println(test(200, 300))  //60000
29 }
匿名函数

    d. 多返回值

使用type定义函数类型: type type_name func 函数名 (参数列表) [(返回值列表)],例如:

 1 package main
 2 
 3 import "fmt"
 4 
 5 //定义函数类型
 6 type add_func func(int, int) int
 7 
 8 func add(a, b int) int {
 9     return a + b
10 }
11 
12 // error 因为上面定义的函数类型add_func接收两个参数,下面定义三个参数。
13 // func add(a, b, c int) int {
14 //     return a + b
15 // }
16 
17 func sub(a, b int) int {
18     return a - b
19 }
20 
21 func operator(op add_func, a int, b int) int {
22     return op(a, b)
23 }
24 
25 func main() {
26     c := add
27     fmt.Println(c)
28     sum := operator(c, 100, 200)
29     fmt.Println(sum)  //300
30 
31     res := operator(sub, 100, 200)
32     fmt.Println(res)  //-100
33 }
定义函数类型

3. 函数参数传递方式:
    1). 值传递
    2). 引用传递
    注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决                   于拷贝的对象大小,对象越大,则性能越低。
    注意2:map、slice、chan、指针、interface默认以引用的方式传递。

4. 命名返回值的名字

 1 package main 
 2 
 3 import "fmt"
 4 
 5 func add(a, b int) (sum int) {
 6     sum = a + b
 7     return
 8 }
 9 
10 // 等价于
11 // func add(a, b int) int {
12 //     sum = a + b
13 //     return sum
14 // }
15 
16 func calc(a, b int) (sum int, avg int) {
17     sum = a + b
18     avg = (a +b)/2
19     return
20 }
21 
22 // 等价于
23 // func calc(a, b int) (int, int) {
24 //     sum = a + b
25 //     avg = (a +b)/2
26 //     return sum, avg
27 // }
28 
29 
30 func main() {
31     add_res := add(100, 200)
32     fmt.Println(add_res) //300
33     sum, avg := calc(100, 200)
34         fmt.Println(sum) //300
35         fmt.Println(avg) //150
36 }
命名返回值的名字

5. _标识符,用来忽略返回值

 1 package main 
 2 
 3 import "fmt"
 4 
 5 func calc(a, b int) (sum int, avg int) {
 6     sum = a + b
 7     avg = (a +b)/2
 8     return
 9 }
10 
11 func main() {
12     sum, _ := calc(100, 200)
13     fmt.Println(sum) //300
14 }
忽略返回值

6. 可变参数

注意:其中arg是一个slice,通过len(arg)来判断传递参数的个数,通过arg[index]依次访问所有参数。

//0个或多个参数
func add(arg…int) int {
}//1个或多个参数
func add(a int, arg…int) int {
}//2个或多个参数
func add(a int, b int, arg…int) int {
}

练习14:写一个函数add,支持1个或多个int相加,并返回相加结果。
练习15:写一个函数concat,支持1个或多个string相拼接,并返回结果。

 1 package main
 2 
 3 import "fmt"
 4 
 5 func add(a int, arg ...int) int {
 6     var sum int = a
 7     for i := 0; i < len(arg); i++ {
 8         sum += arg[i]
 9     }
10 
11     return sum
12 }
13 
14 func concat(a string, arg ...string) (result string) {
15     result = a
16     for i := 0; i < len(arg); i++ {
17         result += arg[i]
18     }
19 
20     return
21 }
22 
23 func main() {
24     sum := add(10, 3, 3, 3, 3)
25     fmt.Println(sum) //22
26 
27     res := concat("hello", " ", "world")
28     fmt.Println(res) //hello world
29 }
可变参数

7. defer用途
    1). 当函数返回时,执行defer语句。因此,可以用来做资源清理。
    2). 多个defer语句,按先进后出的方式执行。
    3). defer语句中的变量,在defer声明时就决定了。

 1 package main 
 2 
 3 import "fmt"
 4 
 5 func test() {
 6     i := 0
 7     defer fmt.Println(i)
 8     i++
 9     return
10 } 
11 
12 func main() {
13     test() // 0
14 }
example1
 1 package main 
 2 
 3 import "fmt"
 4 
 5  func test() {
 6     for i := 0; i < 5; i++ {
 7         defer fmt.Printf("%d ", i)
 8     } 
 9 } 
10 
11 
12 func main() {
13     test() // 4 3 2 1 0
14 }
example2

defer几个常用用途:

(1). 关闭文件句柄

1 func read() {
2     file := open(filename)
3     defer file.Close()
4     
5     //文件操作
6 }
关闭文件句柄

(2). 锁资源释放

1 func read() {
2     mc.Lock()
3     defer mc.Unlock()
4     //其他操作
5 }
锁资源释放

(3). 数据库连接释放

1 func read() {
2     conn := openDatabase()
3     defer conn.Close()
4     //其他操作
5 }
数据库连接释放

练习:

1.编写程序,在终端输出九九乘法表。

 1 package main 
 2 
 3 import "fmt"
 4 
 5 func mutil() {
 6     for i := 1; i <= 9; i++ {
 7         for j := 1; j <= i; j++ {
 8             fmt.Printf("%d*%d=%d\t", i, j, i*j)
 9         }
10         fmt.Printf("\n")
11     }
12 }
13 
14 func main() {
15     mutil()
16 }
练习1

2.一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3编程找出1000以内的所有完数。

 1 package main 
 2 
 3 import "fmt"
 4 
 5 func isPerfNum(num int) bool {
 6     res := 0
 7     for i := 1; i < num; i++ {
 8         if num % i == 0 {
 9             res += i
10         }
11     }
12 
13     return res == num
14 }
15 
16 func process(n int) {
17     for i := 1; i <= n; i++ {
18         if isPerfNum(i) {
19             fmt.Println(i)
20         } 
21     }
22 }
23 
24 func main() {
25     var num int
26     fmt.Println("Input a number >> ")
27     fmt.Scanf("%d", &num)
28     process(num)
29 }
练习2

3.输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到左读完全相同的字符串。

 1 package main 
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func isPalindNum(str string) bool {
 8     flag := true
 9     for i := 0; i <= int(len(str)/2); i++ {
10         if str[i] != str[len(str)-i-1] {
11             flag = false
12             break
13         }
14     }
15 
16     return flag
17 }
18 
19 func main() {
20     var str string
21     fmt.Println("Input a string >> ")
22     fmt.Scanf("%s", &str)
23     if isPalindNum(str) {
24         fmt.Printf("%s is a palindrome number.", str)
25     }
26 }
练习3 V1(无法处理汉字回文数)
 1 package main 
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func isPalindNum(str string) bool {
 8     temp := [] rune(str) //注意这块的处理
 9     flag := true
10     for i := 0; i <= int(len(temp)/2); i++ {
11         if temp[i] != temp[len(temp)-i-1] {
12             flag = false
13             break
14         }
15     }
16 
17     return flag
18 }
19 
20 func main() {
21     var str string
22     fmt.Println("Input a string >> ")
23     fmt.Scanf("%s", &str)
24     if isPalindNum(str) {
25         fmt.Printf("%s is a palindrome number.", str)
26     }
27 }
练习3 V2(完整版)

4.输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "bufio"
 7 )
 8 
 9 func count(str string) (charCount, spaceCount, numberCount, otherCount int) {
10     t := [] rune(str)
11     for _, v := range t {
12         switch {
13             case v >= 'A' && v <= 'Z':
14                 fallthrough
15             case v >= 'a' && v <= 'z':
16                 charCount++
17             case v == ' ':
18                 spaceCount++
19             case v >= '0' && v <= '9':
20                 numberCount++
21             default:
22                 otherCount++
23         }
24     }
25     return
26 }
27 
28 
29 func main() {
30     reader := bufio.NewReader(os.Stdin)
31     result, _, err := reader.ReadLine()
32     if err != nil {
33         fmt.Println("read from console err:", err)
34         return
35     }
36     cc, sc, nc, oc := count(string(result)) //注意:result为type []byte,因此需要强制转换为string类型
37     fmt.Printf("charCount = %d, spaceCount = %d, numberCount = %d, otherCount = %d", cc, sc, nc, oc)
38 }
练习4

5. 计算两个大数相加的和,这两个大数会超过int64的表示范围。

  1 package main 
  2 
  3 import (
  4     "fmt"
  5     "os"
  6     "bufio"
  7     "strings"
  8 )
  9 
 10 func add(str1, str2 string) (result string) {
 11     var left int = 0  //进位
 12 
 13     if len(str1) == 0 || len(str2) == 0 {
 14         result = "0"
 15         return
 16     }
 17 
 18     index1 := len(str1) - 1
 19     index2 := len(str2) - 1
 20     //处理重合部分
 21     for index1 >= 0 && index2 >= 0 {
 22         c1 := str1[index1] - '0'
 23         c2 := str2[index2] - '0'
 24 
 25         sum := int(c1) + int(c2) + left
 26         if sum >= 10 {
 27             left = 1
 28         } else {
 29             left = 0
 30         }
 31 
 32         c3 := (sum%10) + '0'
 33         result = fmt.Sprintf("%c%s", c3, result)
 34 
 35         index1--
 36         index2--
 37     }
 38 
 39     //处理str1长度大于str2情况
 40     for index1 >= 0 {
 41         c1 := str1[index1] - '0'
 42 
 43         sum := int(c1) + left
 44         if sum >= 10 {
 45             left = 1
 46         } else {
 47             left = 0
 48         }
 49 
 50         c3 := (sum%10) + '0'
 51         result = fmt.Sprintf("%c%s", c3, result)
 52 
 53         index1--
 54     }
 55 
 56     //处理str1长度小于str2情况
 57     for index2 >= 0 {
 58         c2 := str2[index2] - '0'
 59 
 60         sum := int(c2) + left
 61         if sum >= 10 {
 62             left = 1
 63         } else {
 64             left = 0
 65         }
 66 
 67         c3 := (sum%10) + '0'
 68         result = fmt.Sprintf("%c%s", c3, result)
 69 
 70         index2--
 71     }
 72 
 73     //处理str1长度等于str2情况
 74     if left == 1 {
 75         result = fmt.Sprintf("1%s", result)
 76     }
 77     return
 78 }
 79 
 80 func main() {
 81     fmt.Println("please input a+b >>")
 82     //从console端读取数据
 83     reader := bufio.NewReader(os.Stdin)
 84     result, _, err := reader.ReadLine()
 85     if err != nil {
 86         fmt.Println("read from console err:", err)
 87         return
 88     }
 89     
 90     //获取加数与被加数
 91     strSlice := strings.Split(string(result), "+")
 92     if len(strSlice) != 2 {
 93         fmt.Println("please input a+b")
 94         return
 95     }
 96 
 97     //去除左右空格
 98     str1 := strings.TrimSpace(strSlice[0])
 99     str2 := strings.TrimSpace(strSlice[1])
100     fmt.Println(add(str1, str2))
101 }
练习5

补充:rune数据类型

例1:

1 package main
2 
3 import "fmt"
4 
5 func main() {
6 
7     var str = "hello 你好"
8     fmt.Println("len(str):", len(str)) //len(str): 12
9 }
example

为何输出12?

golang中string底层是通过byte数组实现的。中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码是utf-8。因此输出12。

例2:

 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6 
 7     var str = "hello 你好"
 8     fmt.Println("len(str):", len(str)) //len(str): 12
 9 
10     temp := [] rune(str)
11     fmt.Println("len(temp):", len(temp)) //len(temp): 8
12 }
example2

现在来看rune数据类型官方解释:

 rune is an alias for int32 and is equivalent to int32 in all ways. It is used, by convention, to distinguish character values from integer values.

rune是int32的别名,几乎在所有方面等同于int32,它用来区分字符值和整数值。type rune = int32。

如果我们预期想得到一个字符串的长度,而不是字符串底层占得字节长度,该怎么办?

例3:

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "unicode/utf8"
 6 )
 7 
 8 func main() {
 9 
10     var str = "hello 你好"
11     // 方法1:
12     //golang中的unicode/utf8包提供了用utf-8获取长度的方法
13     fmt.Println("RuneCountInString:", utf8.RuneCountInString(str))  //RuneCountInString: 8
14 
15     //方法2:
16     //通过rune类型处理unicode字符
17     temp := [] rune(str)
18     fmt.Println("rune:", len(temp))  //rune: 8
19 }
example3

例4:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8 
 9     var str = "hello 你好"
10     for i := 0; i < len(str); i++ {
11         fmt.Println(str[i])
12     }
13 
14     fmt.Println("--------")
15 
16     temp := [] rune(str)
17     for i := 0; i < len(temp); i++ {
18         fmt.Println(temp[i])
19     }
20 }
21 
22 //输出结果
23 // 104
24 // 101
25 // 108
26 // 108
27 // 111
28 // 32
29 // 228
30 // 189
31 // 160
32 // 229
33 // 165
34 // 189
35 // --------
36 // 104
37 // 101
38 // 108
39 // 108
40 // 111
41 // 32
42 // 20320
43 // 22909
example4

总结:

golang中一个byte数据类型与rune相似,它们都是用来表示字符类型的变量类型。它们的不同在于:
(1). byte 等同于int8,常用来处理ascii字符。
(2). rune 等同于int32,常用来处理unicode或utf-8字符。

参考文献:

  • https://www.jianshu.com/p/4fbf529926ca

转载于:https://www.cnblogs.com/xuejiale/p/10364745.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/387432.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ教程总结

【译】RabbitMQ教程一 主要通过Hello Word对RabbitMQ有初步认识 【译】RabbitMQ教程二 工作队列&#xff0c;即一个生产者对多个消费者循环分发、消息确认、消息持久、公平分发 【译】RabbitMQ教程三 如何同一个消息同时发给多个消费者开始引入RabbitMQ消息模型中的重要概念路由…

机器学习实战(笔记)------------KNN算法

1.KNN算法 KNN算法即K-临近算法&#xff0c;采用测量不同特征值之间的距离的方法进行分类。 以二维情况举例&#xff1a; 假设一条样本含有两个特征。将这两种特征进行数值化&#xff0c;我们就可以假设这两种特种分别为二维坐标系中的横轴和纵轴&#xff0c;将一个样本以点的形…

Java注解Annotation 完成验证

Java注解Annotation用起来很方便&#xff0c;也越来越流行&#xff0c;由于其简单、简练且易于使用等特点&#xff0c;很多开发工具都提供了注解功能&#xff0c;不好的地方就是代码入侵比较严重&#xff0c;所以使用的时候要有一定的选择性。 这篇文章将利用注解&#xff0c;来…

隐藏马尔科夫模型HMM

概率图模型 HMM 先从一个具体的例子入手,看看我们要解决的实际问题.例子引自wiki.https://en.wikipedia.org/wiki/Hidden_Markov_model Consider two friends, Alice and Bob, who live far apart from each other and who talk together daily over the telephone about what …

阿里云天池 金融风控训练营Task1 广东工业站

Task1 赛题理解 一、学习知识点概要 本次学习先是介绍了赛题的背景和概况&#xff0c;题目以金融风控中的个人信贷为背景&#xff0c;给所给的47列特征中&#xff0c;根据贷款申请人的数据信息预测其是否有违约的可能&#xff0c;以此判断是否通过贷款。随后介绍了比赛中的评…

如何将.crt的ssl证书文件转换成.pem格式

如何将.crt的ssl证书文件转换成.pem格式摘自&#xff1a;https://www.landui.com/help/show-8127 2018-07-04 14:55:41 2158次 准备:有一台安装了php的linux操作系统执行下面的openssl命令即可&#xff1a;openssl x509 -in www.xx.com.crt -out www.xx.com.pem转载于:https://…

SpringMVC学习记录--Validator验证分析

一.基于Validator接口的验证. 首先创建User实例,并加入几个属性 ?12345678910111213141516171819202122232425262728293031323334<code class"hljs cs">public class User {private String username;private String password;private String nickname;public …

C# 获取句柄程序

这个小程序需要用到系统API&#xff0c;也就是需要用到user32中的三个函数。 第一个&#xff1a;WindowFromPoint 返回一个窗口句柄 第二个&#xff1a;GetWindowText 获取窗口标题 第三个&#xff1a;GetClassName 获取类名 当然&#xff0c;最重要的一点就是要引用命名空间…

centos7安装oracle12c 一

本文 基本参考了下面这篇文章http://blog.csdn.net/gq5251/article/details/42004035 和http://www.linuxidc.com/Linux/2017-08/146528.htm 但是改正了一些错误操作系统:CentOS Linux release 7.2.1511 (Core) oracle: oarcle (12.1.0.2.0) - Standard Edition (SE2)几点要注…

阿里云天池 Python训练营Task4: Python数据分析:从0完成一个数据分析实战 学习笔记

本学习笔记为阿里云天池龙珠计划Python训练营的学习内容&#xff0c;学习链接为&#xff1a;https://tianchi.aliyun.com/specials/promotion/aicamppython?spm5176.22758685.J_6770933040.1.6f103da1tESyzu 一、学习知识点概要 本次主要通过阿里云天池的赛题【Python入门系…

JMETER从JSON响应中提取数据

如果你在这里&#xff0c;可能是因为你需要使用JMeter从Json响应中提取变量。 好消息&#xff01;您正在掌握掌握JMeter Json Extractor的权威指南。作为Rest API测试指南的补充&#xff0c;您将学习掌握Json Path Expressions 所需的一切。 我们走吧&#xff01;并且不要惊慌&…

centos7安装oracle12c 二

环境&#xff1a;CentOS7VMware12&#xff0c;分配资源&#xff1a;CPU&#xff1a;2颗&#xff0c;内存&#xff1a;4GB&#xff0c;硬盘空间&#xff1a;30GB Oracle 12C企业版64位 下载地址&#xff1a;http://www.oracle.com/technetwork/database/enterprise-edition/down…

阿里云天池 Python训练营Task5:Python训练营测试 学习笔记

一、学习知识点概要 本次是Python训练营的测试&#xff0c;在45分钟内完成25题&#xff0c;满分100分及格80分。题目主要考察Task1到Task3里面的Python基础知识。在我随到的25道题里&#xff0c;知识点有&#xff1a; 变量&#xff08;包括数据类型和容器类型&#xff09;运算…

centos7安装oracle12c 三

场景描述&#xff1a;我在自己电脑的虚拟机上linux环境下安装oracle11g数据库。 Linux版本为&#xff1a;CentOS release 6.8 (Final)&#xff0c;Oracle版本为&#xff1a;linux.x64_11gR2 问题描述&#xff1a;在oracle安装到Prerequisite Checks这一步的时候&#xff0c;出现…

《属性数据分析引论》 部分课后习题R语言实践(第三章、第四章)

目录 前言 第三章 广义线性模型 习题3.18 a小题 b小题 c小题 d小题 习题3.19 a小题 b小题 c小题 第四章 Logistic回归 习题4.1 a小题 b小题 c小题 d小题 e小题 习题4.2 a小题 b小题 c小题 d小题 小结 前言 习题选自高等教育出版社译制&#xff0c;Alan A…

Linux下SVN搭建

在Linux系统中搭建svn服务所需要用到的软件叫做subversion&#xff0c;可以通过yum来进行安装&#xff0c;如图 安装好软件后第一件事就是创建一个仓库目录 [rootserver1 ~]# mkdir /svn 使用svn自带命令建立仓库 [rootserver1 ~]# svnadmin create /svn 进入该仓库&#xff0c…

可用于 线性判别、聚类分析 的R语言函数总结

一、判别分析 判别分析是一种分类技术&#xff0c;其通过一个已知类别的“训练样本”来建立判别准则&#xff0c;并通过预测变量来为未知类别的数据进行分类。根据判别的模型分为线性判别和非线性判别&#xff0c;线性判别中根据判别准则又分为Fisher判别&#xff0c;Bayes判别…

Android APK 打包过程 MD

Markdown版本笔记我的GitHub首页我的博客我的微信我的邮箱MyAndroidBlogsbaiqiantaobaiqiantaobqt20094baiqiantaosina.comAndroid APK 打包流程 MD 目录 目录APK 的打包流程整体流程资源的编译和打包资源ID资源索引概况具体打包过程aapt阶段aidl阶段Java Compiler阶段dex阶段a…

可用于 主成分分析、R型因子分析、简单相应分析 的R语言函数总结

一、主成分分析 主成分分析是多元统计分析的一种常用的降维方法&#xff0c;它以尽量少的信息损失&#xff0c;最大程度将变量个数减少&#xff0c;且彼此间互不相关。提取出来的新变量成为主成分&#xff0c;主成分是原始变量的线性组合。 1.1 KMO检验和Bartlett球形检验 在…

持续集成之Jenkins安装部署

安装JDKJenkins是Java编写的&#xff0c;所以需要先安装JDK&#xff0c;这里采用yum安装&#xff0c;如果对版本有需求&#xff0c;可以直接在Oracle官网下载JDK。 [rootlinux-node1 ~]# yum install -y java-1.8.0 安装Jekins [rootlinux-node1 ~]# cd /etc/yum.repos.d/ […