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
Go语言学习之3 流程控制、函数相关推荐
- Go语言学习14-基本流程控制
基本流程控制 Go语言在流程控制结构方面有些像C语言,但是在很多方面都与C不同.特点如下: 在Go语言中没有 do 和 while 循环,只有一个更加广义的 for 语句. Go语言中的 switch ...
- C#面向对象程序设计课程实验一:实验名称:C#语言基础、程序流程控制
C#面向对象程序设计课程实验一:实验名称:C#语言基础.程序流程控制 实验内容:C#语言基础.程序流程控制 一. 实验目的 二.实验环境 三.实验内容 四.实验总结 实验内容:C#语言基础.程序流程控 ...
- C语言学习笔记(8)函数
C语言学习笔记(8)函数 函数 函数主要是用于将解决复杂的编程问题分解为数个可以分开进行解决的小问题,通过函数分装,最后在拼连在一起.有利于多人协作开发. 函数同样需要先声明后调用,声明符号为 voi ...
- Python语言学习之lambda:lambda函数的简介、使用方法、案例大全之详细攻略
Python语言学习之lambda:lambda函数的简介.使用方法.案例大全之详细攻略 目录 lambda函数的简介 1.lambda匿名函数的格式 2.lambda函数特点 3.lambda函数与 ...
- Python语言学习之字母L开头函数使用集锦:logging日志用法之详细攻略
Python语言学习之字母L开头函数使用集锦:logging日志用法之详细攻略 目录 logging日志用法之详细攻略 logging日志用法之详细攻略 K Llogging.basicConfig( ...
- Python语言学习之字母E开头函数使用集锦:endswith使用用法之详细攻略
Python语言学习之字母E开头函数使用集锦:endswith使用用法之详细攻略 目录 endswith用法之详细攻略 enumerate()函数 endswith用法之详细攻略 if my_file ...
- Python语言学习之字母D开头函数使用集锦:del、dict使用方法之详细攻略
Python语言学习之字母D开头函数使用集锦:del.dict使用方法之详细攻略 目录 del.dict使用方法 del dict() #创建字典 del.dict使用方法 del a=1, ...
- Python语言学习之字母G开头函数使用集锦:global用法之详细攻略
Python语言学习之字母G开头函数使用集锦:global用法之详细攻略 global全局变量用法 global全局变量:python使用的变量默认一定是用局部变量:如果想使用作用域之外的全局变量,则 ...
- Python语言学习之字母A开头函数使用集锦:assert用法之详细攻略
Python语言学习之字母A开头函数使用集锦:assert用法之详细攻略 assert断言的用法 assert断言用法:防御性的编程.运行时对程序逻辑的检测.合约性检查(比如前置条件,后置条件).程序 ...
最新文章
- VTL-vm模板的变量用法
- 算法笔记_120:蓝桥杯第六届省赛(Java语言B组部分习题)试题解答
- Asp.net中的路由
- webpack笔记(2)打包src下的html文件
- cvc降噪和主动降噪_降噪蓝牙耳机哪款好?300内建议入手的五款主动降噪蓝牙耳机...
- php 接口继承,详细对比php中类继承和接口继承
- mysql的瓶颈_MySQL瓶颈分析与优化
- postmessage 游戏窗口内无效_前端的微前端在交通项目内的应用实践
- 我的内核学习笔记13:x86平台linux系统重启流程跟踪
- 程序员面试谈薪的背后的事,你一定要看看
- 1.6秒能干什么?自动锁螺丝机表演给你看
- Laravel 源码解读
- 宠物商店——三层架构
- QQ浏览器9 主页无法修改成功的解决办法
- 2015年数模B题学习报告
- 第三届“传智杯”全国大学生IT技能大赛(初赛)-Java B组题解
- 嵌入式单片机基础篇(二十七)之Stm32F103单片机给蓝牙模块发送AT指令程序
- Conflux尚书详解区块链不可能三角突围战
- 周志华老师报告Boasting 25years
- Stata:多个变量组间均值\中位数差异检验
热门文章
- java秒杀时间与服务器时间_Javascript实现秒杀倒计时(时间与服务器时间同步)...
- java二嗨租车项目_Java入门第二季6-1租车项目代码
- linux live cd ubuntu,在Windows 7上体验Ubuntu Live CD
- php访问服务器文件路径,PHP与服务器文件系统的简单交互
- cdockpane限制调整大小_影视后期制作小伙伴必看:使用AU对声音质量进行调整的三大技巧...
- 域名自动跳转不搭建服务器,宝塔搭建的服务器WEB系统环境如果做域名301跳转
- vscode自动格式化不符合eslint_VsCode(Visual Studio Code)格式化代码符合EsLint
- python 线程异步执行踩坑
- Redis对象的refcount与lru属性(内存回收、对象共享、空转时长)
- Java LocalDate类| parse()方法与示例