Go语言系列之基础函数和流程控制
一、strings和strconv的使用
-
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中首次出现的位置,如果没有出现,则返回-1
-
4. strings.LastIndex(s string, str string) int:判断str在s中最后出现的位置,如果没有出现,则返回-1
-
5. strings.Replace(str string, old string, new string, n int):字符串替换
-
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):去掉字符串首尾空白字符
-
11. strings.Trim(str string, cut string):去掉字符串首尾cut字符
-
12. strings.TrimLeft(str string, cut string):去掉字符串首cut字符
-
13. strings.TrimRight(str string, cut string):去掉字符串首cut字符
-
14. strings.Field(str string):返回str空格分隔的所有子串的slice
-
15. strings.Split(str string, split string):返回str split分隔的所有子串的slice
-
16. strings.Join(s1 []string, sep string):用sep把s1中的所有元素链接起来
-
17. strings.Itoa(i int):把一个整数i转成字符串
-
18. strings.Atoi(str string)(int, error):把一个字符串转成整数
练习1:判断一个url是否以http://开头,如果不是,则加上http://,判断一个路径是否以“/”结尾,如果不是,则加上/。
package main import ( "fmt" "strings" ) func urlProcess(url string) string { result := strings.HasPrefix(url, "http://") if !result { url = fmt.Sprintf("http://%s", url) } return url } func pathProcess(path string) string { result := strings.HasSuffix(path, "/") if !result { path = fmt.Sprintf("%s/", path) } strings.Replace() return path } func main() { var ( url string path string ) fmt.Printf("请输入一个url地址和path路径:") fmt.Scanf("%s%s", &url, &path) url = urlProcess(url) path = pathProcess(path) fmt.Println(url) fmt.Println(path) } // 请输入一个url地址和path路径: www.baidu.com c:/python
练习2:写一个函数分别演示Replace、Count、Repeat、ToLower、ToUpper等的用法
package main import ( "fmt" "strconv" "strings" ) func main() { str := " hello world abc \n" result := strings.Replace(str, "world", "you", 1) fmt.Println("replace:", result) count := strings.Count(str, "l") fmt.Println("count:", count) result = strings.Repeat(str, 3) fmt.Println("repeat:", result) result = strings.ToLower(str) fmt.Println("tolower:", result) result = strings.ToUpper(str) fmt.Println("toupper:", result) result = strings.TrimSpace(str) fmt.Println("trimspace:", result) result = strings.Trim(str, " \n\r") fmt.Println("trim", result) result = strings.TrimLeft(str, " \n\r") fmt.Println("trimleft:", result) result = strings.TrimRight(str, " \n\r") fmt.Println("trimright:", result) split_result := strings.Fields(str) for i := 0; i < len(split_result); i++ { fmt.Println(split_result[i]) } split_result = strings.Split(str, "l") for i := 0; i < len(split_result); i++ { fmt.Println(split_result[i]) } str2 := strings.Join(split_result, "l") fmt.Println("join:", str2) str2 = strconv.Itoa(1000) fmt.Println("Itoa:", str2) num, err := strconv.Atoi(str2) if err != nil { fmt.Println("can not convert str to int", err) } fmt.Println("number is:", num) }
二、时间和日期类型
- 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"))
练习:写一个程序,获取当前时间,并格式化成 2017/06/15 08:05:00形式, 统计一段代码的执行耗时,单位精确到微秒。
package main import ( "fmt" "time" ) func test() { time.Sleep(time.Millisecond * 100) } func main() { now := time.Now() fmt.Println(now.Format("2006/01/02 15:04:05")) start := time.Now().UnixNano() // 1970年到现在的纳秒数 test() end := time.Now().UnixNano() fmt.Println("cost:%d us\n", (end-start)/1000) }
三、指针类型
-
1. 普通类型,变量存的就是值,也叫值类型
-
2. 获取变量的地址,用&,比如: var a int, 获取a的地址:&a
-
3. 指针类型,变量存的是一个地址,这个地址存的才是值
-
4. 获取指针类型所指向的值,使用:*,比如:var *p int, 使用*p获取p指向的值
练习:写一个程序,获取一个变量的地址,并打印到终端,写一个函数,传入一个int类型的指针,并在函数中修改所指向的值。在main函数中调用这个函数,并把修改前后的值打印到终端,观察结果
package main import "fmt" func modify(n *int) { fmt.Println(n) *n = 10000000 return } func main() { var a int = 10 // 整数类型 fmt.Println(&a) // 取地址 fmt.Println(a) // 取变量值 var p *int // 指针类型 p = &a fmt.Println(p) // 取地址 fmt.Println(*p) // 取指针指向的变量值 *p = 100 // 修改指针地址指向的变量值 fmt.Println(a) // 响应的a的变量值也更改 var b int = 999 p = &b *p = 5 fmt.Println(a) fmt.Println(b) modify(&a) fmt.Println(a) }
四、流程控制
1. if / else 分支判断
方式一: if condition1 { } 方式二: if condition1 { } else { 方式三: } if condition1 { } else if condition2 { } else if condition3 { } else { } 方式四: if condition1 { } else { }
例子
package main import “fmt” func main() { bool1 := true if bool1 { fmt.Printf(“The value is true\n”) } else { fmt.Printf(“The value is false\n”) } }
练习:写一个程序,从终端读取输入,并转成整数,如果转成整数出错,则输出 “can not convert to int”,并返回。否则输出该整数。
package main import ( "fmt" "strconv" ) func main() { var str string fmt.Printf("请输入一个字符串:") fmt.Scanf("%s", &str) number, err := strconv.Atoi(str) if err != nil { fmt.Println("convert failed, err:", err) return } fmt.Println(number) }
2. switch case语句
语法
switch var { case var1: case var2: case var3: default: }
写法
写法一 var i = 0 switch i { case 0: case 1: fmt.Println(“1”) case 2: fmt.Println(“2”) default: fmt.Println(“def”) } 写法二 var i = 0 switch i { case 0: fallthrough case 1: fmt.Println(“1”) case 2: fmt.Println(“2”) default: fmt.Println(“def”) } 写法三 var i = 0 switch i { case 0, 1: fmt.Println(“1”) case 2: fmt.Println(“2”) default: fmt.Println(“def”) } 写法四 var i = 0 switch { condition1: fmt.Println(“i > 0 and i < 10”) condition2: fmt.Println(“i > 10 and i < 20”) default: fmt.Println(“def”) } 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(“def”) } 写法五 switch i := 0 { 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”) }
练习:猜数字,写一个程序,随机生成一个0到100的整数n,然后用户在终端,输入数字,如果和n相等,则提示用户猜对了。如果不相等,则提示用户,大于或小于n。
package main import ( "fmt" "math/rand" ) func main() { var n int n = rand.Intn(100) fmt.Println(n) for { var input int fmt.Printf("请输入一个0-100的整数:") fmt.Scanf("%d\n", &input) flag := false switch { case input == n: flag = true fmt.Println("you are right") case input < n: fmt.Printf("%d is smaller\n", input) case input > n: fmt.Printf("%d is bigger\n", input) } if flag { break } } }
3. for 语句
写法1
for 初始化语句; 条件判断; 变量修改 { } for i := 0 ; i < 100; i++ { fmt.Printf(“i=%d\n”, i) }
练习:写一个程序,在终端打印如下图形
A
AA
AAA
AAAA
AAAAA
package main import "fmt" func Print(n int) { for i := 1; i <= n; i++ { for j := 0; j < i; j++ { fmt.Printf("A") } fmt.Println() } } func main() { Print(6) }
写法二
for 条件 { }
for i > 0 { fmt.Println(“i > 0”) } for true { fmt.Println(“i > 0”) } for { fmt.Println(“i > 0”) }
写法三 for range语句
str := “hello world,中国” for i, v := range str { fmt.Printf(“index[%d] val[%c] len[%d]\n”, i, v, len([]byte(v))) }
用来遍历数组、slice、map、chan
写法四 break,coutinue语句
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(v))) }
4. goto和label语句
package main import "fmt" func main() { LABEL1: for i := 0; i <= 5; i++ { for j := 0; j <= 5; j++ { if j == 4 { continue LABEL1 } fmt.Printf("i is: %d, and j is: %d\n", i, j) } } } package main func main() { i := 0 HERE: print(i) i++ if i == 5 { return } goto HERE }
五、函数
1. 语法
声明语法:func 函数名 (参数列表) [(返回值列表)] {}
2. golang 函数特点
-
a. 不支持重载,一个包不能有两个名字一样的函数
-
b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
-
c. 匿名函数
-
d. 多返回值
例
package main import "fmt" func add(a, b int) int { return a + b } func test() { return } func main() { c := add sum := c(200, 300) fmt.Println(sum) str := "hello world,中国" for index, val := range str { fmt.Printf("index[%d] val[%c] len[%d]\n", index, val, len([]byte(string(val)))) } }
例2
package main import "fmt" type op_func func(int, int) int func add(a, b int) int { return a + b } func sub(a, b int) int { return a - b } func operator(op func(int, int) int, a, b int) int { return op(a, b) } func main() { var c op_func c = add // c := add sum := operator(c, 100, 200) dif := operator(sub, 100, 200) fmt.Println(sum) fmt.Println(dif) }
3. 函数传参的两种方式
1). 值传递
2) 引用传递
注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
注意2:map、slice、chan、指针、interface默认以引用的方式传递
package main import "fmt" func modify(a int) { a = 100 } func main() { a := 8 fmt.Println(a) modify(a) fmt.Println(a) }
4. 命名返回值的名字
func add(a, b int) (c int) { c = a + b return } func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return }
5. _标识符,用来忽略返回值
func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return} func main() { sum, _ := calc(100, 200) }
6. 可变参数
注意:其中arg是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数
练习:写一个函数add,支持1个或多个int相加,并返回相加结果, 写一个函数concat,支持1个或多个string相拼接,并返回结果
package main import "fmt" func add(a int, arg ...int) int { var sum int = a for i := 0; i < len(arg); i++ { sum += arg[i] } return sum } func concat(a string, arg ...string) (result string) { result = a for i := 0; i < len(arg); i++ { result += arg[i] } return } func main() { sum := add(10, 3, 5, 6, 6) fmt.Println(sum) res := concat("hello", " ", "world") fmt.Println(res) }
7. defer用途
- 1). 当函数返回时,执行defer语句。因此,可以用来做资源清理
- 2). 多个defer语句,按先进后出的方式执行
- 3). defer语句中的变量,在defer声明时就决定了。
关闭文件句柄
func read() { file := open(filename) defer file.Close() //文件操作 }
锁资源释放
func read() { mc.Lock() defer mc.Unlock() //其他操作 }
数据库连接释放
func read() { conn := openDatabase() defer conn.Close() //其他操作 }
defer示例
package main import "fmt" var ( result = func(a1 int, b1 int) int { return a1 + b1 } ) func test(a, b int) int { result := func(a1 int, b1 int) int { return a1 + b1 }(a, b) return result } func main() { fmt.Println(test(100, 200)) fmt.Println(result(100, 200)) var i int = 0 // defer语句编译的时候会把语句放入栈中,函数结尾的时候一个一个出栈执行 defer fmt.Println(i) defer fmt.Println("second") i = 10 fmt.Println(i) }
本节作业
-
1. 编写程序,在终端输出九九乘法表。
-
2. 一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3.编程找出1000以内的所有完数。
-
3. 输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到左读完全相同的字符串。
-
4. 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
-
5. 计算两个大数相加的和,这两个大数会超过int64的表示范围.
参考
package main import "fmt" func multi() { for i := 1; i < 10; i++ { for j := 1; j <= i; j++ { fmt.Printf("%d*%d=%d\t", i, j, i*j) } fmt.Println() } } func main() { multi() }
package main import "fmt" func perfect(n int) bool { var sum int = 0 for i := 1; i < n; i++ { if n%i == 0 { sum += i } } return sum == n } func process(n int) { var flag bool = false for i := 1; i < n+1; i++ { if perfect(i) { flag = true fmt.Println(i, "是完数") } } if flag == false { fmt.Println(n, "以内没有完数") } } func main() { var n int fmt.Printf("请输入一个数字:") fmt.Scanf("%d", &n) process(n) }
package main import "fmt" func process(str string) bool { // rune代表一个字符(中文英文都可以) // byte代表一个字节,一个中文字符代表三个字节 t := []rune(str) length := len(t) for i, _ := range t { if i == length/2 { break } last := length - i - 1 if t[i] != t[last] { return false } } return true } func main() { var str string fmt.Printf("请输入一个字符串:") fmt.Scanf("%s", &str) if process(str) { fmt.Println(str, "是回文: yes") } else { fmt.Println(str, "是回文: no") } }
package main import ( "bufio" "fmt" "os" ) func process(str string) (word_count int, sapce_counr int, number_count int, other_count int) { t := []rune(str) for _, v := range t { switch { case v >= 'a' && v <= 'z': fallthrough case v >= 'A' && v <= 'Z': word_count++ case v == ' ': sapce_counr++ case v >= '0' && v <= '9': number_count++ default: other_count++ } } return } func main() { fmt.Printf("请输入一个字符串:") reader := bufio.NewReader(os.Stdin) result, _, err := reader.ReadLine() if err != nil { fmt.Println("read from console err", err) return } wc, sc, nc, oc := process(string(result)) fmt.Printf("word_count:%d\nspace_count:%d\nnumber_count:%d\nother_count:%d", wc, sc, nc, oc) }
package main import ( "bufio" "fmt" "os" "strings" ) func multi(str1, str2 string) (result string) { if len(str1) == 0 && len(str2) == 0 { result = "0" return } var index1 = len(str1) - 1 var index2 = len(str2) - 1 var left int for index1 >= 0 && index2 >= 0 { c1 := str1[index1] - '0' c2 := str2[index2] - '0' sum := int(c1) + int(c2) + left if sum >= 10 { left = 1 } else { left = 0 } c3 := (sum % 10) + '0' result = fmt.Sprintf("%c%s", c3, result) index1-- index2-- } for index1 >= 0 { c1 := str1[index1] - '0' sum := int(c1) + left if sum >= 10 { left = 1 } else { left = 0 } c3 := (sum % 10) + '0' result = fmt.Sprintf("%c%s", c3, result) index1-- } for index2 >= 0 { c1 := str2[index2] - '0' sum := int(c1) + left if sum >= 10 { left = 1 } else { left = 0 } c3 := (sum % 10) + '0' result = fmt.Sprintf("%c%s", c3, result) index2-- } if left == 1 { result = fmt.Sprintf("1%s", result) } return } func main() { fmt.Printf("请输入一个字符串:") reader := bufio.NewReader(os.Stdin) result, _, err := reader.ReadLine() if err != nil { fmt.Println("read from console err", err) return } strSlice := strings.Split(string(result), "+") if len(strSlice) != 2 { fmt.Println("please input a+b") return } strNumber1 := strings.TrimSpace(strSlice[0]) strNumber2 := strings.TrimSpace(strSlice[1]) fmt.Println(multi(strNumber1, strNumber2)) }