golang(3):strings和strconv使用 & 时间和日期类型 & 指针类型 & 流程控制 & 函数
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): // 字符串替换; 如果 n<0,表示全部替换 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): // 去掉字符串首尾空白字符;\n 也会去掉 strings.Trim(str string, cut string): // 去掉字符串首尾cut字符 func Trim(s string, cutset string) string ---> 去掉字符串s中首部以及尾部与字符串cutset中每个相匹配的字符,如: ---> s="hello yes",cutset="he",那么s的结果为:"llo yes" strings.TrimLeft(str string, cut string): // 去掉字符串首cut字符 strings.TrimRight(str string, cut string): // 去掉字符串尾cut字符 11. strings.Fields(str string): // 返回str空格分隔的所有子串的slice strings.Split(str string, split string): // 返回str split分隔的所有子串的slice 12. strings.Join(s1 []string, sep string): // 用sep把s1中的所有元素链接起来 13. strconv.Itoa(i int): // 把一个整数i转成字符串 <---> fmt.Sprintf("%d",str) 14. strconv.Atoi(str string)(int, error): // 把一个字符串转成整数
15. strings.Contains(s string, substr string) bool: // 是否包含
参考链接: https://www.cnblogs.com/action-go/p/11560190.html
示例代码1:
package main import ( "fmt" "strings" ) func urlProcess(url string) string { result := strings.HasPrefix(url,"http://") // strings.HasPrefix(变量,匹配内容) 返回一个 bool 值 if !result{ url = fmt.Sprintf("http://%s",url) } return url } func pathProcess(path string) string { result := strings.HasSuffix(path,"/") // strings.HasSuffix(变量,匹配内容) 返回一个 bool 值 if !result{ path = fmt.Sprintf("%s/",path) } return path } func main (){ var ( url string path string ) fmt.Scanf("%s%s",&url,&path) url = urlProcess(url) path = pathProcess(path) fmt.Println(url) fmt.Println(path) } // 运行结果: [root@NEO example01_string01]# go run main/main.go 10.0.0.8/login f:/learning http://10.0.0.8/login f:/learning/ [root@NEO example01_string01]#
# 示例代码2:
package main import ( "fmt" "strings" "strconv" ) func main(){ str := " hello world abc \n" result := strings.Replace(str,"abc","neo",1) // 字符串替换 fmt.Println("Replace:",result) count := strings.Count(str,"o") // 字符串计数 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) // 去掉字符串首尾空白字符;\n 也会去掉 fmt.Println("TrimSpace:",result) result = strings.Trim(str," \n\r") // 去掉字符串首尾 cutset 字符 fmt.Println("Trim:",result) result = strings.TrimLeft(str," \n\r") // 去掉左侧 fmt.Println("TrimLeft:",result) result = strings.TrimRight(str," \n\r") // 去掉右侧 fmt.Println("TrimRight:",result) splitResult := strings.Fields(str) // 以空格为分隔符切割字符串,返回数组 for i := 0; i<len(splitResult);i++ { fmt.Printf("fieldsResult[%d]=%s\n",i,splitResult[i]) } splitResult = strings.Split(str,"o") // 以"o"为分隔符切割字符串,返回数组 for i := 0; i<len(splitResult);i++ { fmt.Printf("splitResult[%d]=%s\n",i,splitResult[i]) } str2 := strings.Join(splitResult,"o") // 拼接字符串 fmt.Println("Join:",str2) str2 = strconv.Itoa(100) // 数字转字符串 fmt.Println("Itoa:",str2) num,err := strconv.Atoi(str2) // 字符串转数字;有两个返回值 if err != nil { fmt.Println("can not convert to int",err) return } fmt.Println("Atoi:",num) } // 编译后执行结果如下: [root@NEO project]# go build -o bin/example01_string02 go_dev/day03/example01_string02/main [root@NEO project]# bin/example01_string02 Replace: hello world neo Count: 2 Repeat: hello world abc hello world abc hello world abc ToLower: hello world abc ToUpper: HELLO WORLD ABC TrimSpace: hello world abc Trim: hello world abc TrimLeft: hello world abc TrimRight: hello world abc fieldsResult[0]=hello fieldsResult[1]=world fieldsResult[2]=abc splitResult[0]= hell splitResult[1]= w splitResult[2]=rld abc Join: hello world abc Itoa: 100 Atoi: 100 [root@NEO project]#
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()…)
// %02d : 02 modified %d (an adverb !) to pad the result with zeros to exactly 8 digits. (用0把结果填充到2位数字) 6. time.Duration用来表示纳秒 7. 一些常量: const ( Nanosecond Duration = 1 * Nanosecond 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:05”)) fmt.Println(now.Format(“2006/1/02 15:04”)) fmt.Println(now.Format(“2006/1/02”))
示例3:
写一个程序,获取当前时间,并格式化成 2017/06/15 08:05:00 形式
写一个程序,统计一段代码的执行耗时,单位精确到微秒。
// 示例代码如下: package main import ( "fmt" "time" ) func test_runtime(){ time.Sleep(time.Millisecond * 100) // 停 100 毫秒 } func main (){ now := time.Now() // 方式一 fmt.Printf("%02d/%02d/%02d %02d/%02d/%02d\n",now.Year(),now.Month(),now.Day(),now.Hour(),now.Minute(),now.Second()) // 方式二: time 自带一个 Format() 函数 fmt.Println(now.Format("2006-01-02 15:04:05")) start := time.Now().UnixNano() // 获取当前时间戳(纳秒级) test_runtime() end := time.Now().UnixNano() fmt.Printf("runtime:%d us\n",(end-start)/1000) } // 运行结果如下: [root@NEO example01_string03]# go run main/main.go 2019/07/19 00/11/35 2019-07-19 00:11:35 runtime:100255 us [root@NEO example01_string03]#
指针类型
1. 普通类型,变量存的就是值,也叫值类型 2. 获取变量的地址,用&,比如: var a int, 获取a的地址:&a 3. 指针类型,变量存的是一个地址,这个地址存的才是值 4. 获取指针类型所指向的值,使用:*,比如:var *p int, 使用*p获取p指向的值
示例4:
写一个程序,获取一个变量的地址,并打印到终端。
写一个函数,传入一个int类型的指针,并在函数中修改所指向的值。在main函数中调用这个函数,并把修改前后的值打印到终端,观察结果
// 示例代码如下: package main import ( "fmt" ) func pointer_val(p *int){ // 该函数的参数p需要传入一个地址 *p = 2 // 修改 指针p 指向的值 } func main(){ str := "hello world" fmt.Println("addr=",&str) num := 1 var p *int // 声明一个 int 类型的指针;p 里面存的是地址 p = &num // 给指针类型的变量赋值时,需要赋值一个地址(&变量);取出指针 p 所指向的值 ---> *p fmt.Println("p=",p) fmt.Println("pointer_val_before=",*p) pointer_val(p) // p 参数是一个地址 fmt.Println("pointer_val_after=",*p) } // 运行结果如下: [root@NEO example03_pointer01]# go run main/main.go addr= 0xc0000101e0 p= 0xc0000120b0 pointer_val_before= 1 pointer_val_after= 2 [root@NEO example03_pointer01]#
流程控制
# if语句: // 1、 if condition1 { } // 2、 if condition1 { } else { } // 3、 if condition1 { } else if condition2 { } else if condition3 { } else { } # switch case 语句 // 语法: switch var { // var 就变量 case var1: case var2: case var3: default: } // 形式1: var i = 0 switch i { case 0: fallthrough // fallthrough 具有 穿透 的作用 case 1: fmt.Println(“1”) // go switch 的 case 后不需要加 break case 2,3,4,5: fmt.Println(“2”) default: fmt.Println(“def”) } // 形式2: 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”) }
示例4:猜数字,写一个程序,随机生成一个0到100的整数n,然后用户在终端,输入数字,如果和n相等,则提示用户猜对了。如果不相等,则提示用户,大于或小于n。
// 示例代码: package main import ( "fmt" "math/rand" ) func main(){ var n int n = rand.Intn(100) // 生成随机数 for { flag := false var input int fmt.Scanf("%d\n",&input) // %d\n --> 以 换行作为分隔符 switch { case input == n: fmt.Println("you are right") flag = true case input > n: fmt.Println("bigger") default: fmt.Println("smaller") } if flag { break } } }
for 语句
// 方式一: for 初始化语句; 条件判断; 变量修改 { } // 方式二: for 条件 { } // 方式三:for range 语句 --> 用来遍历数组、slice、map、chan str := "hello world,中国" for i, v := range str { // i表示下标, v 表示值 fmt.Printf("index[%d] val[%c] len[%d]\n", i, v, len([]byte(string(v)))) // len([]byte(string(v))) --> 表示字符的长度 } // 方式四: 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)))) } // 方式五:goto 和 label 语句 // label语句1: package main import "fmt" func main() { LABEL1: // label语法 ---> 字符: for i := 0; i <= 5; i++ { for j := 0; j <= 5; j++ { if j == 4 { continue LABEL1 // 会跳转到 LABEL1 处继续执行 } fmt.Printf("i is: %d, and j is: %d\n", i, j) } } } // goto label 语句2: package main func main() { i := 0 HERE: print(i) i++ if i == 5 { return } goto HERE // 会跳转到 HERE 处继续执行 ; 此 goto label 实现了一个 for 循环 (只能在同一个函数中跳转) }
示例5:写一个程序,在终端打印如下图形
A
AA
AAA
AAAA
AAAAA
// 示例代码如下: package main import ( "fmt" ) func print(n int) { for i := 0; i < n; i++ { for j := 0; j < i; j++ { fmt.Printf("A") } fmt.Println() } } func main() { print(5) }
示例6:(上述的方式三)
// 示例代码: package main import "fmt" func main() { str := "hello world,中国" for i, v := range str { // i表示下标, v 表示值 fmt.Printf("index[%d] val[%c] len[%d]\n", i, v, len([]byte(string(v)))) // len([]byte(string(v))) --> 表示字符的度 } } // 运行结果如下: [root@NEO example04_for01]# go run main/main.go index[0] val[h] len[1] index[1] val[e] len[1] index[2] val[l] len[1] index[3] val[l] len[1] index[4] val[o] len[1] index[5] val[ ] len[1] index[6] val[w] len[1] index[7] val[o] len[1] index[8] val[r] len[1] index[9] val[l] len[1] index[10] val[d] len[1] index[11] val[,] len[1] index[12] val[中] len[3] index[15] val[国] len[3] [root@NEO example04_for01]#
函数
golang函数特点: // a. 不支持重载,一个包不能有两个名字一样的函数 // b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量 // c. 匿名函数 // d. 多返回值
示例7:自定义一种函数类型,作为参数传入另一个函数的参数
package main import "fmt" type calc_func func(int, int) int // type --> 自定义一种类型 calc_func:calc_func 是函数类型,该类型有两个参数均为 int,返回值也是 int func add(a int, b int) int { return a + b } func operator(op calc_func,a int, b int) int { // op 参数为自定义的 函数类型;函数当作参数传给另一个函数 return op(a,b) } func main(){ c := add fmt.Println(c) // c 是函数 add 的内存地址 sum := operator(c,100,200) fmt.Println(sum) } // 运行结果如下: [root@NEO example05_func01]# go run main/main.go 0x487170 300 [root@NEO example05_func01]#
函数参数传递方式:
1). 值传递 2). 引用传递 注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。 注意2:map、slice、chan、指针、interface默认以引用的方式传递
函数命名返回值的名字,如下:
func add(a, b int) (c int) { // c 就是返回值 c = a + b return } func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return }
_ 标识符,用来忽略返回值,如下:
func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return } func main() { sum, _ := calc(100, 200) }
函数的可变参数,如下:
func add(arg…int) int { // 0个或多个参数 } func add(a int, arg…int) int { // 1个或多个参数 } func add(a int, b int, arg…int) int { // 2个或多个参数 } // 注意:其中arg是一个slice(切片,可理解成数组/列表),我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数
示例8:
写一个函数add,支持1个或多个int相加,并返回相加结果
写一个函数concat,支持1个或多个string相拼接,并返回结果
// 示例代码如下: package main import "fmt" func add(a int,arg...int) (sum int){ sum += a for i := 0; i < len(arg); i++{ sum += arg[i] } return } func concat(s string,arg...string)(result string){ result += s for i := 0; i < len(arg); i++{ result += arg[i] } return } func main(){ sum := add(1,2) fmt.Println(sum) sum = add(1,2,3) fmt.Println(sum) result := concat("hello"," world") fmt.Println(result) result = concat("hello"," world"," neo") fmt.Println(result) } // 运行结果如下: [root@NEO example05_func02]# go run main/main.go 3 6 hello world hello world neo [root@NEO example05_func02]#
函数 defer:
// 1. 当函数返回时,执行defer语句。因此,可以用来做资源清理 // 2. 多个defer语句,按先进后出的方式执行 (栈) // 3. defer语句中的变量,在defer声明时就决定了。
示例代码:
package main import "fmt" func a(){ i := 0 defer fmt.Println("func a defer",i) // 执行这个声明的时候,i 的值已经确实为0,此时语句还没有执行,该语句是在函数返的时候才执行 i++ fmt.Println("func a",i) // 先执行这行代码的 Println,再执行 defer 中的 Println } func f(){ for i := 0; i < 3; i++ { defer fmt.Println("func f defer",i) // 先执行后面的 defer 语句 } } func main(){ a() f() } // 运行结果如下: [root@NEO example05_defer]# go run main/main.go func a 1 func a defer 0 func f defer 2 func f defer 1 func f defer 0 [root@NEO example05_defer]# // defer用途(伪代码): // 1. 关闭文件句柄 func read() { //文件操作 file := open(filename) defer file.Close() } // 2. 锁资源释放 func read() { mc.Lock() defer mc.Unlock() } // 3. 数据库连接释放 func read() { conn := openDatabase() defer conn.Close() }
示例题:
1. 编写程序,在终端输出九九乘法表。
// 示例代码: package main import "fmt" func multi() { for i := 1; i <= 9; i++{ for j :=1; j<=i; j++ { fmt.Printf("%d*%d=%d ",j,i,i*j) } fmt.Println() } } func main(){ multi() }
2. 一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3。编程找出1000以内的所有完数。
package main import "fmt" func perfect(n int) bool { var sum int for i :=1; i < n; i++{ if n%i == 0 { sum += i // 把该数的所有因子加起来 } } return n == sum } func process(n int){ for i := 1; i <= n; i++{ if perfect(i){ fmt.Println(i) } } } func main(){ var n int fmt.Scanf("%d",&n) process(n) }
3. 输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到左读完全相同的字符串。
// 示例代码: package main import "fmt" func process(s string) bool { for i := 0; i < len(s)/2; i++{ // 从字符串的两边向中间靠拢 if s[i] != s[len(s)-1-i]{ return false } } return true } func main(){ var s string fmt.Scanf("%s\n",&s) result := process(s) if result { fmt.Printf("%s is huiwen\n",s) } else { fmt.Printf("%s not huiwen\n",s) } }
4. 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
package main import ( "fmt" "bufio" "os" ) func count(s string) (charCount, spaceCount, numCount, otherCount int){ t := []rune(s) // 转换类型 for _,v := range t { switch { case v >= 'A' && v <= 'z': // 比较是在 ASCII 中的位置数字; byte 型的只能用单引号 charCount++ case v == ' ': spaceCount++ case v >= '0' && v <= '9': numCount++ default: otherCount++ } } return } func main (){ reader := bufio.NewReader(os.Stdin) // bufio.NewReader() 实例化一个对象;os.Stdin 标准输入 result, _, err := reader.ReadLine() // 从终端读取输入;返回的第一个参数 (result) 是 []byte if err != nil { fmt.Println("Read from console err:",err) return } fmt.Println(result) cc, sc, nc, oc := count(string(result)) // 先把 result 转换成 string 类型 fmt.Printf("word count:%d\n space count:%d\n number count:%d\n others count:%d\n",cc,sc,nc,oc) } // byte 等同于int8,常用来处理ascii字符 // rune 等同于int32,常用来处理unicode或utf-8字符 // 运行结果如下: [root@NEO example06_count]# go run main/main.go hello 123-= [104 101 108 108 111 32 49 50 51 45 61] word count:5 space count:1 number count:3 others count:2 [root@NEO example06_count]#
5. 计算两个大数相加的和,这两个大数会超过int64的表示范围.
package main import ( "fmt" ) func fillZero(s string, n int)string{ var res string = s for i:=1; i<=n; i++{ res = fmt.Sprintf("%c%s",'0',res) } return res } func plus(a string, b string) string { var index,carry,length int // index 表示从右开始的个数; carry 表示进位(相加满十进一);length 表示两个数字字符长度 var str_plus string // 长度小的在前面填充 0 len1 := len(a) len2 := len(b) if (len1==0 && len2==0){ return "0" } switch { case len1 > len2: n := len1 - len2 res := fillZero(b,n) b = res length = len1 case len1 < len2: n := len2 - len1 res := fillZero(a,n) a = res length = len2 default: length = len1 } // 各位相加 for (index <= length-1) { byte_a := a[length-1-index] - '0' // 数字对应的字符 减去 '0' 字符,就是该数字的值;uint8 类型 byte_b := b[length-1-index] - '0' sum := int(byte_a) + int(byte_b) + carry if sum >= 10 { carry = 1 } else { carry = 0 } byte_new := (sum % 10) + '0' str_plus = fmt.Sprintf("%c%s",byte_new,str_plus) index++ } if carry == 1{ str_plus = fmt.Sprintf("1%s",str_plus) } return str_plus } func main(){ var a, b string fmt.Scanf("%s %s\n",&a, &b) res_plus := plus(a,b) fmt.Println(res_plus) }
Code your future.