概要:
1.strings与strconv的使用
2.Go中的时间和日期类型
3.流程控制
4.函数详解
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:转为大写 9. strings.TrimSpace(str string):去掉字符串首尾空白字符 strings.Trim(str string, cut string):去掉字符串首尾cut字符 strings.TrimLeft(str string, cut string):去掉字符串首cut字符 strings.TrimRight(str string, cut string):去掉字符串首cut字符 10. strings.Field(str string):返回str空格分隔的所有子串的slice strings.Split(str string, split string):返回str split分隔的所有子串的slice 11. strings.Join(s1 []string, sep string):用sep把s1中的所有元素链接起来 12. strconv.Itoa(i int):把一个整数i转成字符串 13. strconv.Atoi(str string)(int, error):把一个字符串转成整数
练习:
练习1:判断一个url是否以http://开头,如果不是,则加上http://。
练习2:判断一个路径是否以“/”结尾,如果不是,则加上/。
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) } return path } func main() { var url string var path string fmt.Scanf("%s%s" ,&url,&path) result_url := urlProcess(url) result_path := pathProcess(path) fmt.Println(result_url) fmt.Println(result_path) } /*
输入: www.baidu.com c:/study
输出: http://www.baidu.com c:/study/ */
练习:
package main import ( "strings" "fmt" "strconv" ) func main() { str := "hello world world " result := strings.Index(str,"h") //获取index,首次出现h的位置,获取不到返回-1 fmt.Println("Index is :",result) result = strings.LastIndex(str,"l") //获取str中l最后出现的位置,没有返回-1 fmt.Println("LastIndex is :",result) replaceResult := strings.Replace(str,"world","myself",1) //替换当最后的int为-1时候,替换所有,等于0的时候不替换 fmt.Println("Replace is :",replaceResult) count := strings.Count(str,"l") //求某个字符串出现的次数 fmt.Println("count is :",count) repeatResult := strings.Repeat(str,2) //字符串重复几次 fmt.Println("repeat_result is :",repeatResult) tolowerResult := strings.ToLower(str) //全部变小写 fmt.Println("tolower_result is :",tolowerResult) toupperResult := strings.ToUpper(str) //全部变大写 fmt.Println("toupper_result is :",toupperResult) trimspaceResult := strings.TrimSpace(str) //去掉左右两头空格,默认 也会去掉 fmt.Println("trimspace result is :",trimspaceResult) trimResult := strings.Trim(str," ") //自定义替换方式 fmt.Println("trims result is :",trimResult) trimLeftResult := strings.TrimLeft(str," ") //去掉左侧的 fmt.Println("trimLeftspace result is :",trimLeftResult) trimRightResult := strings.TrimRight(str," ") //去掉右侧的 fmt.Println("trimRightspace result is :",trimRightResult) feildResult := strings.Fields(str) //将字符串以数组形式返回,默认以空格切割 for i := 0; i < len(feildResult) ; i++ { fmt.Println(feildResult[i]) } spiltResult := strings.Split(str,"l") //将字符串以l切割 for i := 0; i < len(spiltResult) ; i++ { fmt.Println(spiltResult[i]) } joinResult := strings.Join(spiltResult,"l") //将数组join到一期 fmt.Println("join str is ",joinResult) myInt := 100 itoaResult := strconv.Itoa(myInt) //将整数转化为字符串 fmt.Println("itoa is ",itoaResult) atoiResult,err := strconv.Atoi(itoaResult) //将字符串转化为整数 if err != nil{ fmt.Println("this is not convert :",err) } fmt.Println("atoi is :",atoiResult) } /* Index is : 0 LastIndex is : 15 Replace is : hello myself world count is : 4 repeat_result is : hello world world hello world world tolower_result is : hello world world toupper_result is : HELLO WORLD WORLD trimspace result is : hello world world trims result is : hello world world trimLeftspace result is : hello world world trimRightspace result is : hello world world hello world world he o wor d wor d join str is hello world world itoa is 100 atoi is : 100 */
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”))
练习:
练习1:写一个程序,获取当前时间,并格式化成 2017/06/15 08:05:00形式
练习2:写一个程序,统计一段代码的执行耗时,单位精确到微秒。
package main import ( "time" "fmt" ) func test(){ time.Sleep(time.Millisecond * 100) } func main() { nowTime := time.Now() fmt.Println(nowTime.Format("2006/01/02 15:04:05")) startTime := time.Now().UnixNano() test() endTime := time.Now().UnixNano() fmt.Printf("cost time is %d us ",(endTime - startTime) / 1000) } /* 2018/05/05 20:03:11 cost time is 103321 us */
指针类型
练习:
练习1:写一个程序,获取一个变量的地址,并打印到终端。
练习2:写一个函数,传入一个int类型的指针,并在函数中修改所指向的值。在main函数中调用这个函数,并把修改前后的值打印到终端,观察结果
package main import "fmt" func test(p *int ){ fmt.Println(p) *p = 10000 return } func main() { var a int = 10 fmt.Println(&a) //获取内存地址 var p *int //定义一个指针 p = &a *p = 20 fmt.Println(*p) //打印指针对应的数值 fmt.Println(a) var b int = 999 p = &b //将指针p的内存地址改为了b,修改指针p的值对b无影响 *p = 5 fmt.Println(a) fmt.Println(b) test(&a) //将内存地址传如函数,函数内修改指针对应的值,影响a fmt.Println(a) } /* 0xc42007e008 20 20 20 5 0xc42007e008 10000 */
流程控制
1. if/else
练习:
写一个程序,从终端读取输入,并转成整数,如果转成整数出错,则输出 “can not convert to int”,并返回。否则输出该整数。
package main import ( "fmt" "strconv" ) func main() { var a string fmt.Scanf("%s",&a) number, err := strconv.Atoi(a) if err != nil { fmt.Println("this is not convert ",err) } fmt.Println(number) } /* sdad this is not convert strconv.Atoi: parsing "sdad": invalid syntax */
1. switch case
switch写法一:
package main import "fmt" func main() { var a int = 100 switch a { //switch 不需要加break,跟shell中的case很像 case 100: fmt.Println("this is 0") fallthrough //执行后继续往下走 不判断 case 10: fmt.Println("this is 10") case 0,1,2,3,4,5: //多个条件都走一个分支 fmt.Println("1,2,3,4,5,0 is ok") default: fmt.Println("this is default") } }
switch写法二:
package main import "fmt" func main() { var a int = 5 switch { case a >0 && a < 10: fmt.Println(" a > 0 & a < 10") case a >10 && a < 20: fmt.Println("a > 10 & a < 20") default: fmt.Println("default") } }
switch写法三:
package main import "fmt" func main() { switch a :=5; { //直接赋值 case a >0 && a < 10: fmt.Println(" a > 0 & a < 10") case a >10 && a < 20: fmt.Println("a > 10 & a < 20") default: fmt.Println("default") } }
练习:
猜数字,写一个程序,随机生成一个0到100的整数n,然后用户在终端,输入数字,如果和n相等,则提示用户猜对了。如果不相等,则提示用户,大于或小于n。
package main import ( "fmt" "math/rand" ) func main() { num := rand.Intn(100) for { var input int fmt.Scanf("%d ",&input) flag := false switch { case num == input: fmt.Println("you are right") flag = true case input < num: fmt.Println("less") case input > num: fmt.Println("bigger") } if flag{ break } } }
for循环练习:
package main import "fmt" func Print(n int ){ for i := 1; i < n+1 ; i++ { for j := 0; j < i ;j++ { fmt.Printf("A") } fmt.Println() } } func main() { Print(6) } /* A AA AAA AAAA AAAAA AAAAAA */
for与range合用:
用来遍历数组、slice、map、chan
package main import "fmt" func main() { var word string = "hello world ,中国" for key,value := range word { //range比遍历数组 fmt.Printf("key[%d],value[%c],len[%d] ",key,value,len([]byte(string(value)))) //cannot convert value (type rune) to type []byte --- value是rune字符型 } } /* key[0],value[h],len[1] key[1],value[e],len[1] key[2],value[l],len[1] key[3],value[l],len[1] key[4],value[o],len[1] key[5],value[ ],len[1] key[6],value[w],len[1] key[7],value[o],len[1] key[8],value[r],len[1] key[9],value[l],len[1] key[10],value[d],len[1] key[11],value[ ],len[1] key[12],value[,],len[1] key[13],value[中],len[3] //中文是三个字符 key[16],value[国],len[3] */
for中goto和label使用
例子1:
package main import "fmt" func main() { LABLE1: for i := 0; i < 5; i++{ for j :=0 ; j < 5 ;j++{ if j == 4 { //当j等于4的时候就跳到LABLE1下在执行,不会只跳过j循环 continue LABLE1 } fmt.Printf("i:[%d],j:[%d] ",i,j) } } } /* i:[0],j:[0] i:[0],j:[1] i:[0],j:[2] i:[0],j:[3] i:[1],j:[0] i:[1],j:[1] i:[1],j:[2] i:[1],j:[3] i:[2],j:[0] i:[2],j:[1] i:[2],j:[2] i:[2],j:[3] i:[3],j:[0] i:[3],j:[1] i:[3],j:[2] i:[3],j:[3] i:[4],j:[0] i:[4],j:[1] i:[4],j:[2] i:[4],j:[3] */
例子2:
package main import "fmt" func main() { LABLE1: for i := 0; i < 5; i++{ for j :=0 ; j < 5 ;j++{ if j == 4 { //当j等于4的时候就跳到LABLE1下在执行,不会只跳过j循环 goto LABLE1 } fmt.Printf("i:[%d],j:[%d] ",i,j) } } }
函数
go函数特点:
a. 不支持重载,一个包不能有两个名字一样的函数
b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
c. 匿名函数
d. 多返回值
package main import "fmt" type op_func func(int ,int ) int //通过type定义了一个函数类型 func add (a,b int) int { //这个传入和返回值必须和定义的一致 return a + b } func sub (a,b int) int { return a - b } func operator(a,b int , op op_func) int { return op(a,b) } func main() { //c := add //sum := operator(100,200,c) sum := operator(100,200,sub) //直接传入函数名也可以 fmt.Println(sum) }
错误例子:
package main import "fmt" type add_func func(int, int) int func add(a, b, c int) int { //这里传了3个值,但是定义类型的时候传入的是2个,所以会编译不过去 return a + b } func operator(op add_func, a int, b int) int { return op(a, b) } func main() { c := addfmt.Println(c) sum := operator(c, 100, 200) fmt.Println(sum) }
函数参数传递方式:
1). 值传递
2). 引用传递
注意:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。默认传递一个函数名字是8字节
map、slice、chan、指针、interface默认以引用的方式传递
命名返回值的名字:
func add(a, b int) (c int) { c = a + b //这里不需要做变量定义直接赋值即可 return } func calc(a, b int) (sum int, avg int) { sum = a + bavg = (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) }
可变参数:
arg ...int
告诉Go这个函数接受不定数量的参数。注意,这些参数的类型全部是int
。在函数体中,变量arg
是一个int
的slice
:
for _, n := range arg { fmt.Printf("And the number is: %d ", n) }
练习:
1.f写一个函数add,支持1个或多个int相加,并返回相加结果
2.写一个函数concat,支持1个或多个string相拼接,并返回结果
package main import "fmt" func add_avg (a int,arg ...int) int{ // arg ...int 可变长参数 sum := 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_avg(10,100,1000) fmt.Println(sum) res := concat("hello"," ","myself") fmt.Println(res) }
defer用途:
1. 当函数返回时,执行defer语句。因此,可以用来做资源清理
2. 多个defer语句,按先进后出的方式执行 栈的模式
3. defer语句中的变量,在defer声明时就决定了。
4. defer在return或者函数结束后执行,从栈中后进先出的方式出栈
5.Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题
package main import "fmt" //def read(){ // conn,err := openConn() // // defer func(){ //匿名函数与defer结合 // if conn != nil { // conn.Close() // } // }() // //} var ( result = func(a,b int) int{ //定义一个全局的匿名函数,前提要有变量接收这个匿名函数 return a + b } ) func dtest(a,b int) int{ result := func(a1,b1 int) int{ //定义一个匿名函数 return a1 + b1 }(a,b) return result } func main() { res_1 := result(400,800) fmt.Println(res_1) res := dtest(100,300) fmt.Println(res) i := 0 //首先定义defer不会执行,这个时候i=0,之后无论i怎么修改都不会改变(因为fmt的函数传入的是值类型), // 然后将defer压入栈中,在整个程序执行完毕后,从栈中依次执行 defer fmt.Println(i) defer fmt.Println("second") i = 10 fmt.Println(10) }
defer用途一:
defer用途二:
defer用途三:
匿名函数:
var ( result = func(a,b int) int{ //定义一个全局的匿名函数,前提要有变量接收这个匿名函数 return a + b } ) func dtest(a,b int) int{ result := func(a1,b1 int) int{ //定义一个匿名函数 return a1 + b1 }(a,b) return result }
函数传递指针的优势:
-
- 传指针使得多个函数能操作同一个对象。
- 传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。所以当你要传递大的结构体的时候,用指针是一个明智的选择。
- Go语言中
channel
,slice
,map
这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice
的长度,则仍需要取地址传递指针)
练习:
1.99乘法表:
package main import "fmt" func muitl(){ for i :=1; i < 10 ; i++{ for j :=1; j <= i; j++{ //注意是=号 fmt.Printf("%d*%d=%d ",i,j,i*j) } fmt.Println() } } func main() { muitl() } /* 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 */
2.一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3.编程找出1000以内的所有完数。
package main import "fmt" func perfect(n int) bool{ var sum int = 0 for i := 1;i < n;i++{ if n%i == 0{ //自己取余为0 sum += i } } return sum == n } func process(n int){ for i := 1; i < n+1; i++{ if perfect(i){ fmt.Println(i) } } } func main() { var input int fmt.Scanf("%d",&input) process(input) }
3.输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到左读完全相同的字符串。
package main import "fmt" func reverse(n string) (result bool){ t := []rune(n) length := len(t) for i,_ := range t{ if i == length/2{ //等于中间的下角标就跳出 例如1221 -->到12就停止 break } last := length -i - 1 if t[i] != t[last]{ result = false }else{ result = true } } return } func main() { var input string fmt.Scanf("%s",&input) res := reverse(input) if res{ fmt.Println("ok") }else{ fmt.Println("no") } }
4.输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
package main import ( "bufio" "os" "fmt" ) func count(str string) (wordCount,spaceCount,intCount,otherCount int){ n := []rune(str) //字符slice for _,v := range n{ switch { case v >= 'a' && v <= 'z': fallthrough case v >= 'A' && v <= 'Z': wordCount++ case v >= '0' && v <= '9': intCount++ case v == ' ': spaceCount++ default: otherCount++ } } return } func main() { reader := bufio.NewReader(os.Stdin) //读一行 result,_,err := reader.ReadLine() //返回一行 if err != nil{ fmt.Printf("read from console err:",err) } wc,sc,ic,oc := count(string(result)) fmt.Printf("wordCount=%d spaceCount=%d intCount=%d otherCount=%d",wc,sc,ic,oc) }
5.计算两个大数相加的和,这两个大数会超过int64的表示范围.
package main import ( "bufio" "fmt" "os" "strings" ) //思路 将两个数字变成字符串 跟字符0去做差,然后求和 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' //返回的是str c2 := str2[index2] - '0' //返回的是str sum := int(c1) + int(c2) + left //数字相加进位 if sum >= 10 { left = 1 } else { left = 0 } c3 := (sum % 10) + '0' //取余,在与字符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 { //判断最后的进位是否仍然是1 result = fmt.Sprintf("1%s", result) } return } func main() { 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)) }