Golang之匿名函数和闭包
Go语言支持匿名函数,即函数可以像普通变量一样被传递或使用。
使用方法如下:
main.go
package main import ( "fmt" ) func main() { var v func(a int) int v = func(a int) int { return a * a } fmt.Println(v(6)) //两种写法 v1 := func(i int) int { return i * i } fmt.Println(v1(7)) }
GO语言的匿名函数就是闭包,以下是《GO语言编程》中对闭包的解释
基本概念
闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者
任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含
在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环
境(作用域)。
闭包的价值
闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示
数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到
变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
再次讲解闭包:
一个函数和与其相关的引用环境,组合而成的实体:
package main import "fmt" func main() { var f = Adder() fmt.Println(f(1), "-") fmt.Println(f(20), "-") fmt.Println(f(300), "-") } func Adder() func(int) int { var x int return func(delta int) int { x += delta return x } }
测试文件后缀的闭包。。
package main import ( "fmt" "strings" ) func makeSuffix(suffix string) func(string) string { return func(name string) string { if strings.HasSuffix(name, suffix) == false { return name + suffix } return name } } func main() { //判断字符串 以bmp结尾 f1 := makeSuffix(".bmp") fmt.Println(f1("test")) fmt.Println(f1("pic")) f2 := makeSuffix(".jpg") fmt.Println(f2("test")) fmt.Println(f2("pic")) }
Golang作用域—坑
先举个栗子,全局作用域变量,与 := 符号声明赋值新变量
package main import "fmt" var a = "GG" func main() { n() m() n() } func n() { fmt.Println(a) } func m() { // 对于 := 定义的变量,新变量a与全局已定义的a变量同名,不在一个作用域 //所以golong定义新的变量a。遮住全局变量a,所以m()打印"66" a := "66" fmt.Println(a) }
局部变量
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
以下实例中 main() 函数使用了局部变量 a, b, c:
package main import "fmt" func main() { /* 声明局部变量 */ var a, b, c int /* 初始化参数 */ a = 10 b = 20 c = a + b fmt.Printf ("结果: a = %d, b = %d and c = %d\n", a, b, c) }
全局变量
在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。
全局变量可以在任何函数中使用,以下实例演示了如何使用全局变量:
package main import "fmt" /* 声明全局变量 */ var g int func main() { /* 声明局部变量 */ var a, b int /* 初始化参数 */ a = 10 b = 20 //调用全局变量声明的g g = a + b fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g) }
Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。实例如下:
package main import "fmt" /* 声明全局变量 */ var g int = 20 func main() { /* 声明局部变量 */ var g int = 10 fmt.Printf ("结果: g = %d\n", g) } //结果是g = 10 ,优先考虑局部变量
形式参数
形式参数会作为函数的局部变量来使用。
package main import "fmt" /* 声明全局变量 */ var a int = 20; func main() { /* main 函数中声明局部变量 */ var a int = 10 var b int = 20 var c int = 0 fmt.Printf("main()函数中 a = %d\n", a); c = sum( a, b); fmt.Printf("main()函数中 c = %d\n", c); } /* 函数定义-两数相加 */ func sum(a, b int) int { fmt.Printf("sum() 函数中 a = %d\n", a); fmt.Printf("sum() 函数中 b = %d\n", b); return a + b; }
初始化局部和全局变量
不同类型的局部和全局变量默认值为:
数据类型 | 初始化默认值 |
---|---|
int | 0 |
float32 | 0 |
pointer | nil |
golang之math/rand随机数
简单的随机数生成,结合时间模块初始化种子
package main import ( "fmt" "math/rand" "time" ) func init(){ //以时间作为初始化种子 rand.Seed(time.Now().UnixNano()) } func main() { for i := 0; i < 10; i++ { a := rand.Int() fmt.Println(a) } for i := 0; i < 10; i++ { a := rand.Intn(100) fmt.Println(a) } for i := 0; i < 10; i++ { a := rand.Float32() fmt.Println(a) } }
Golang之fmt格式“占位符”
golang的fmt包实现了格式化I/O函数:
package main import "fmt" type Human struct { Name string } func main() { //普通占位符 var people = Human{Name: "咸鱼兆"} // %+v 添加字段名,输出相应值的默认格式 fmt.Printf("%+v\n", people) //相应值用go语法形式输出 fmt.Printf("%#v", people) //相应值的类型用go语法形式输出 fmt.Printf("%T\n", people) //打印 符号% fmt.Printf("百分比:90%%\n") //布尔占位符 fmt.Printf("%t\n", true) //用二进制表示 //整数占位符 fmt.Printf("%b\n", 5) //相应Unicode码 表示的字符 fmt.Printf("%c\n", 0x4e2d) // 十进制表示 fmt.Printf("%d\n", 0x12) //八进制表示 fmt.Printf("%o\n", 10) //单引号围绕的字符字面值,由Go语法转义 fmt.Printf("%q\n", 0x4e2d) //十六进制表示,字母形式为小写a-f fmt.Printf("%x\n", 13) //十六进制表示,字母形式为小写A-F fmt.Printf("%X\n", 13) //字符串与字节 切片 //输出字符串表示(string类型或[]byte) fmt.Printf("%s\n",[]byte("说Go就Go")) //双引号围绕的字符串,由Go语法安全的转义 fmt.Printf("%q\n","说Go咱就Go") //指针 fmt.Printf("%p\n",&people) //其他标记 只输出ascii编码的字符 fmt.Printf("%+q\n","中文") // }
Golang之字符串操作(反转中英文字符串)
//字符串反转package main import "fmt" func reverse(str string) string { var result string strLen := len(str) for i := 0; i < strLen; i++ { result = result + fmt.Sprintf("%c", str[strLen-i-1]) } return result } func reverse1(str string) string { var result []byte tmp := []byte(str) length := len(str) for i := 0; i < length; i++ { result = append(result, tmp[length-i-1]) } return string(result) } func main() { var str1 = "hello" str2 := "world" str3 := fmt.Sprintf("%s %s", str1, str2) n := len(str3) fmt.Println(str3) fmt.Printf("len(str3)=%d\n", n) substr := str3[0:5] fmt.Println(substr) substr = str3[6:] fmt.Println(substr) result := reverse(str3) fmt.Println(result) result = reverse1(result) fmt.Println(result) }
字符串练习
package main import ( "fmt" ) func testString() { var str = "hello" fmt.Printf("str[0]=%c len(str)=%d\n", str[0], len(str)) for index, val := range str { fmt.Printf("str[%d]=%c\n", index, val) } //str[0] = '0' //fmt.Println("after modify:", str) var byteSlice []byte byteSlice = []byte(str) byteSlice[0] = '0' str = string(byteSlice) fmt.Println("after modify:", str) fmt.Printf("len(str)=%d\n", len(str)) str = "hello, 少林之巅" fmt.Printf("len(str)=%d\n", len(str)) str = "中问123" fmt.Printf("last:len(str)=%d\n", len(str)) var b rune = '中' fmt.Printf("b=%c\n", b) var runeSlice []rune runeSlice = []rune(str) fmt.Printf("str 长度:%d, len(str)=%d\n", len(runeSlice), len(str)) } func testReverseStringV1() { var str = "hello中文 " var bytes []byte = []byte(str) for i := 0; i < len(str)/2; i++ { tmp := bytes[len(str)-i-1] bytes[len(str)-i-1] = bytes[i] bytes[i] = tmp } str = string(bytes) fmt.Println(str) } func testReverseStringV2() { var str = "hello中文 " var r []rune = []rune(str) for i := 0; i < len(r)/2; i++ { tmp := r[len(r)-i-1] r[len(r)-i-1] = r[i] r[i] = tmp } str = string(r) fmt.Println(str) } func testHuiWen() { var str = "上海自来水来自海上" var r []rune = []rune(str) for i := 0; i < len(r)/2; i++ { tmp := r[len(r)-i-1] r[len(r)-i-1] = r[i] r[i] = tmp } str2 := string(r) if str2 == str { fmt.Println(str, " is huiwen") } else { fmt.Println(str, " is not huiwen") } } func main() { //testString() //testReverseStringV2() testHuiWen() }
Golang之strings包
只列举了部分函数方法的使用:
package main import ( "fmt" "strings" ) func main() { Count计算 sep在s中的非重叠个数 func Count(s, substr string) int { s := "Hello,超哥" 统计 l 出现的次数 n := strings.Count(s, "l") fmt.Println(n) //2 如果substr 为空,返回s中字符个数+1 n=strings.Count(s,"") fmt.Println(n) Contains判断 字符串 s中 是否包含 子串 substr func Contains(s, substr string) bool { substr什么都不写,返回true 存在返回true,否则false s := "Hello,超哥!!" b := strings.Contains(s, "!") fmt.Println(b) //true b = strings.Contains(s, "@") //false fmt.Println(b) b=strings.Contains(s,"") fmt.Println(b) ContainsAny 判断字符串 s 中是否 包含 chars 中的任意一个字符 如果char为空,返回false func ContainsAny(s, chars string) bool { s := "Hello,超哥" b := strings.ContainsAny(s,"abc") fmt.Println(b)//false b=strings.ContainsAny(s,"def")//true fmt.Println(b) b=strings.ContainsAny(s,"")//false fmt.Println(b) ContainsRune判断字符串s中是否包含字符r rune不能为空,存在true,否则false func ContainsRune(s string, r rune) bool { s := "Hello,超哥!" b := strings.ContainsRune(s, '\n') fmt.Println(b) //false b = strings.ContainsRune(s, '超') fmt.Println(b) //true b = strings.ContainsRune(s, 'o') fmt.Println(b)//true IndexAny 返回字符串 chars中的任何一个字符 在字符串s中 第一次出现的位置(索引) 找不到返回-1 ,chars为空也返回-1 func strings.IndexAny() s := "Hello,超哥!Hello!" b := strings.IndexAny(s, "abc") fmt.Println(b) //-1 b = strings.IndexAny(s, "") fmt.Println(b) //-1 b = strings.IndexAny(s, "超") fmt.Println(b) LastIndexAny返回字符串chars中的任何一个字符串s中最后一次出现的位置 找不到返回-1,chars为空也返回-1 func LastIndexAny(s, chars string) int { s:="Hello,世界!Hello!" b:=strings.LastIndexAny(s,"abc") fmt.Println(b)//-1 b=strings.LastIndexAny(s,"世") fmt.Println(b)//6 最后一次出现的索引位置 b=strings.LastIndexAny(s,"") fmt.Println(b)//-1 }
比较全的是golang中文网的:https://studygolang.com/articles/5769
package main import "fmt" /* 函数练习, 可变参数使用 写一个函数add 支持1个或多个int相加,并返回相加结果 写一个函数concat,支持1个或多个string拼接,并返回结果 */ func add(a int, arg ...int) 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(10, 3, 3, 3, 3, 3) fmt.Println(sum) res:=concat("hello"," ","大屌") fmt.Println(res) }
九九乘法表:
package main import "fmt" //99乘法表 func multi() { for i := 0; i < 9; i++ { for j := 0; j <= i; j++ { fmt.Printf("%d*%d=%d\t", (i + 1), j+1, (i+1)*(j+1)) } fmt.Println() } } func main() { multi() }
检测回文(中文):
package main import ( "fmt" ) func process(str string) bool { 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.Scanf("%sd", &str) if process(str) { fmt.Println("yes") } else { fmt.Println("no") } }
统计一段字符串,中文,字符,数字,空格,出现的次数:
package main import ( "bufio" "fmt" "os" ) func count(str string) (wordCount, spaceCount, numberCount, otherCount int) { t := []rune(str) for _, v := range t { switch { case v >= 'a' && v <= 'z': fallthrough case v >= 'A' && v <= 'Z': //golang里面++是语句,不能写成表达式 wordCount++ case v == ' ': spaceCount++ case v >= '0' && v <= '9': numberCount++ default: otherCount++ } } return } func main() { reader := bufio.NewReader(os.Stdin) result, _, err := reader.ReadLine() //如果错误不为空,说明有错,就报错 if err != nil { fmt.Println("read from console err:", err) return } wc,sc,nc,oc:=count(string(result)) fmt.Printf("word Count:%d\n space count:%d\n number count:%d\n others count:%d\n",wc,sc,nc,oc) }
golang之panic,recover,defer
defer,recover:
运行时恐慌一旦被引发,就会向调用方传播直至程序崩溃。
recover内建函数用于“拦截”运行时恐慌,可以使当前的程序从恐慌状态中恢复并重新获得流程控制权。
recover函数被调用后,会返回一个interface{}类型的结果。如果当时的程序正处于运行时恐慌的状态,那么这个结果就是非nil的
package main import ( "fmt" "time" ) func test() { defer func() { //defer中使用recover来捕获异常 //defer在函数执行结束最后,执行该方法 if err := recover(); err != nil { fmt.Println(err) } }() b := 0 a := 100 / b fmt.Println(a) return } func main() { for { test() time.Sleep(time.Second) } var a []int a = append(a, 10, 20, 383) a = append(a, a...) fmt.Println(a) }
panic:
为了报告运行期间的致命错误
用于停止当前的控制流程并引发一个运行时错误,它可以接受一个任意类型的参数值,参数值类型常常是string或者error
package main import ( "errors" "fmt" "time" ) func initConfig() (err error) { return errors.New("init config failed") } func test() { //defer func() { // //defer中使用recover来捕获异常 // //defer在函数执行结束最后,执行该方法 // if err := recover(); err != nil { // fmt.Println(err) // } //}() err := initConfig() if err != nil { panic(err) } return } func main() { for { test() time.Sleep(time.Second) } var a []int a = append(a, 10, 20, 383) a = append(a, a...) fmt.Println(a) }
go运行时系统引发的错误,如
func main() { myIndex := 4 ia := [3]int{1, 2, 3} _ = ia[myIndex] }
panic函数传入一个runtime.Error类型的参数值,runtime.Error是一个接口类型,并且内嵌了Go内置的error接口类型。
golang之递归
package main import ( "fmt" "time" ) /* 递归原则,一个大问题分解成相似的小问题 定义好出口条件,否则死循环 */ func calc(n int) int { if n == 1 { return 1 } return calc(n-1) * n } func recusive(n int) { fmt.Println("你好呀") time.Sleep(time.Second) if n > 10 { return } recusive(n + 1) } func factor(n int) int { if n == 1 { return 1 } return factor(n-1) * n } //斐波那 func fab(n int) int { if n <= 1 { return 1 } return fab(n-1) + fab(n-2) } func main() { //fmt.Println(factor(5)) //recusive(0) for i := 0; i < 10; i++ { fmt.Println(fab(i)) } }
golang之数组
1.数组:同一种数据类型的固定长度的序列。
2.数组定义:var a [len]int,例如:var a [5]int
3.长度是数组类型的一部分,因此,var a[5] int 和 var a[10]int 是不同的类型
4.数组可以通过下标进行访问,下标是从0开始,最后一个元素是len-1
for i:=0;i<len(a);i++{
}
5.访问越界,如果下标在数组合法范围之外,就会触发越界,panic异常
package main import "fmt" func main() { var a [10]int a[0] = 100 fmt.Println(a) for i := 0; i < len(a); i++ { fmt.Println(a[i]) } for index, val := range a { fmt.Printf("a[%d]==%d\n", index, val) } }
6.数组是值类型,因此改变副本的值,不会改变本身的值
package main import "fmt" func test2() { var a [10]int b := a b[0] = 100 fmt.Println(a) } //传递指针 func test3(arr *[5]int) { (*arr)[0] = 1000 } func main() { //test2() var a [5]int //传 地址,改变 值类型 test3(&a) fmt.Println(a) }
7.费波纳茨数列
package main import "fmt" //菲波那切数列,非递归方式实现,打印前50个数 func fab(n int){ var a[]uint64 a = make([]uint64,n) a[0]=1 a[1]=1 for i:=2;i<n;i++{ a[i]=a[i-1]+a[i-2] } for _,v:=range a{ fmt.Println(v) } } func main(){ fab(50) }
8.声明数组,遍历数组
package main import "fmt" //数组的初始化 func testArray() { var a [5]int = [5]int{1, 2, 3, 4, 5} var a1 = [5]int{1, 2, 3, 4, 5} var a2 = [...]int{38, 283, 48, 38, 348, 387, 484} var a3 = [...]int{1: 100, 3: 200} var a4 = [...]string{1: "hello", 3: "world"} fmt.Println(a) fmt.Println(a1) fmt.Println(a2) fmt.Println(a3) fmt.Println(a4) } //多维数组 func muchArray() { //两行五列的数组 var a [2][5]int = [...][5]int{{1, 2, 3, 4, 5}, {7, 8, 9, 11, 12}} for row,v:=range a{ for col,v1:=range v{ fmt.Printf("(%d,%d)=%d\n",row,col,v1) } } } func main() { //testArray() muchArray() }
golang之切片
1.切片:切片是数组的一个引用,因此切片是引用类型
2.切片的长度可以改变,因此,切片是个可变的数组。
3.切片遍历方式和数组一样,可以用len()求长度
4.cap可以求出slice最大的容量,0<=cap(slice) <=len(array),其中array是slice引用的数组
5.切片的定义:var 变量名 [ ]类型,例如:var str []string ,var arr [] int
package main import "fmt" //slice,map,channel都是用make初始化 func testSlice() { var slice []int //用数组初始化切片 var arr [5]int = [...]int{1, 2, 3, 4, 5} //arr[start:end] 取头不取尾 //arr[:] 复制一份数组 //去掉切片最后一个元素可以写,slice[:len(slice)-1] //去掉第一个元素就是slice[1:] slice = arr[:] fmt.Println(slice) fmt.Println(len(slice)) fmt.Println(cap(slice)) fmt.Println() slice = slice[0:1] fmt.Println(len(slice)) fmt.Println(cap(slice)) } func main() { testSlice() }
6.切片的内存布局。
7.通过make创建切片
var slice []type=make([]type,len) slice := make([]type,len) slice :=make([]type,len,cap)
8.用append内置函数操作切片
append是双倍cap扩容
string底层就是一个byte的数组,也可以进行切片操作
string底层布局
package main import "fmt" func testSlice() { var a [5]int = [...]int{1, 2, 3, 4, 5} s := a[1:] //切片s是[2,3,4,5] fmt.Printf("before len[%d],cap[%d]\n", len(s), cap(s)) s[1] = 100 //%p 指针 fmt.Printf("s=%p a[1]=%p\n", s, &a[1]) fmt.Println("before a:", a) s = append(s, 10) s = append(s, 10) fmt.Printf("after len[%d] cap[%d]\n", len(s), cap(s)) s = append(s, 10) s = append(s, 10) s = append(s, 10) s[1] = 1000 fmt.Println("after a:", a) fmt.Println(s) fmt.Printf("s=%p a[1]=%p\n", s, &a[1]) //append的...用法 //append会扩容切片容量,默认cap的2倍 fmt.Println("-----分隔符-----(append的...用法)") var a1=[]int{1,2,3} var b=[]int{4,5,6} a1=append(a1,b...) fmt.Println(a1) //切片拷贝,copy不会扩容 fmt.Println("-----分隔符-----(切片拷贝)") s1:=[]int{1,2,3,4,5} s2:=make([]int,10) copy(s2,s1)//结果[1 2 3 4 5 0 0 0 0 0],以s1开头 fmt.Println(s2) //string切片,string本身是不可改的 fmt.Println("-----分隔符-----(string切片)") str:="hello world" res1:=str[0:5] fmt.Println(res1) res2:=str[6:] fmt.Println(res2) } //修改string的方法 //改中文字符一定要用rune,不能用byte func testModifyString(){ fmt.Println("----分隔符----") s:="我hello world" s1:=[]rune(s) s1[0]='你' s1[1]='我' s1[2]='他' str:=string(s1) fmt.Println(str) } func main() { testSlice() testModifyString() }
golang之切片与排序
1.排序与查找操作
排序操作在sort包中,sort.Ints对整数进行排序,sort.Strings对字符串进行排序,sort.Float64对浮点数进行排序
package main import ( "fmt" "sort" ) func testIntSort() { var a = [...]int{1, 8, 38, 2, 348, 484} //数组是值类型,不能直接排序,必须转为切片 sort.Ints(a[:]) fmt.Println(a) } func testStrings() { var a = [...]string{"abc", "efg", "b", "A", "eeee"} //按照字母顺序排序,从小到大 sort.Strings(a[:]) fmt.Println(a) } func testFloat() { var a = [...]float64{2.3, 0.8, 28.2, 392342.2, 0, 6} //从小到大排序 sort.Float64s(a[:]) fmt.Println(a) } func testIntSearch() { var a = [...]int{1, 8, 38, 2, 348, 484} //数组是值类型,不能直接排序,必须转为切片 sort.Ints(a[:]) //SearchInts默认排序后的位置,一定要排序后在查找 index:=sort.SearchInts(a[:],348) fmt.Println(index) } func main() { testIntSort() testStrings() testFloat() testIntSearch() }
golang之map数据类型
package main import "fmt" func testMap() { //两种声明map方式,切记,必须初始化才能用,否则panic //var a map[string]string = map[string]string{ // "key": "value", //} a := make(map[string]string, 10) a["abc"] = "efg" //map的key是唯一的,修改值可以直接改 a["abc"] = "efg2" a["abc1"] = "efg" fmt.Println(a) } //map嵌套map //map是无序排序 func testMap2() { a := make(map[string]map[string]string, 100) a["key1"] = make(map[string]string) a["key1"]["key2"] = "abc" a["key1"]["key3"] = "abc" a["key1"]["key4"] = "abc" a["key1"]["key5"] = "abc" fmt.Println(a) } func modify(a map[string]map[string]string) { _, ok := a["zhangsan"] if !ok { a["zhangsan"] = make(map[string]string) } //与_,ok写法一样 //if a["zhangsan"] == nil {} // a["zhangsan"]["passwd"] = "123456" a["zhangsan"]["nickname"] = "pangpang" return } func testMap3() { a := make(map[string]map[string]string, 100) modify(a) fmt.Println(a) } func trans(a map[string]map[string]string) { for k, v := range a { fmt.Println(k) for k1, v1 := range v { fmt.Println("\t", k1, v1) } } } func testMap4() { a := make(map[string]map[string]string, 100) a["key1"] = make(map[string]string) a["key1"]["key2"] = "abc" a["key1"]["key3"] = "abc" a["key1"]["key4"] = "abc" a["key1"]["key5"] = "abc" //删除map键的内置函数delete //delete(a,"key1") trans(a) fmt.Println(len(a)) } func testMap5() { var a []map[int]int a = make([]map[int]int, 5) //for i:=0;i<5;i++{} //map,slice判断空是nil if a[0] == nil { a[0] = make(map[int]int) } a[0][10] = 10 fmt.Println(a) } func main() { testMap() testMap2() testMap3() testMap4() testMap5() }
map反转
package main import ( "fmt" "sort" ) func testMapSort() { var a map[int]int a = make(map[int]int, 5) a[8] = 10 a[3] = 10 a[2] = 10 a[1] = 10 a[18] = 10 var keys []int for k, _ := range a { keys = append(keys, k) } sort.Ints(keys) for _, v := range keys { fmt.Println(v, a[v]) } } //map反转 func testMapSort1() { var a map[string]int var b map[int]string a = make(map[string]int, 5) b = make(map[int]string, 5) a["abc"] = 101 a["efg"] = 10 for k, v := range a { b[v] = k } fmt.Println(b) } func main() { //testMapSort() testMapSort1() }
来源:https://www.cnblogs.com/bubu99/p/12521682.html