map&函数
map类型
map的申明和定义
- map是一个key-value的数据结构,是引用类型的数据结构,需要初始化
- 初始化的时候容量可以定义,也可以不定义
- map必须初始化才能使用,否则会panic
var a map[key的类型]value的类型
func defineMap() {
var user map[string]int = make(map[string]int)
user["abc"] = 38
fmt.Printf("user:%v\n",user)
a := make(map[string]int)
a["jack"] = 1001
a["handsome"] = 1002
a["shark"] = 1003
//根据key获取value
fmt.Printf("a[jack]=%v\n",a["jack"])
}
Map的使用
- 判定map的长度使用len
- 如何判定map指定的key是否存在: value,ok := map[key]
# 用户角色判定
var whiteUser map[int]bool = map[int]bool {
34123: true,
3456334: true,
1:true,
}
func isWhiteUser(UserId int) bool {
_,ok := whiteUser[UserId]
return ok
}
func main() {
UserId := 1001
if isWhiteUser(UserId) {
fmt.Printf("is white user %v\n",UserId)
}else {
fmt.Printf("is Normal user %v\n",UserId)
}
}
- 遍历操作
func loopMap() {
var m map[string]int
m = map[string]int{
"user01":1001,
"user02":1002,
"user03":1003,
}
for key,val := range m {
fmt.Printf("key:%s,value:%v\n",key,val)
}
}
- 删除元素操作
func delMapkey() {
var m map[string]int
m = map[string]int{
"user01":1001,
"user02":1002,
"user03":1003,
}
delete(m,"user01")
fmt.Printf("%#v\n",m)
fmt.Println(len(m))
}
- map是引用类型(非常重要)
func yinyongMap() {
a := map[string]int {
"jack":1000,
"rose":1001,
}
a["mike"] = 1003
a["jack"] = 999
fmt.Printf("origin map:%v,address:%p\n",a,&a)
b := a
b["mike"] = 1004
fmt.Printf("after map:a=%v,address_a=%p\nmap:b=%v,address_b=%p\n",
a,&a,b,&b)
}
- 有序字典输出(重点)
func youxuMap() {
var m map[string]int
m = map[string]int{
"alice":1001,
"zhansan":1002,
"uloce":1003,
}
var keys[]string
for key,_ :=range m{
keys = append(keys,key)
}
// 按字母有序排序
sort.Strings(keys)
for _,key := range keys {
fmt.Printf("key:%s,value:%v\n",key,m[key])
}
}
- map类型的切片(重点)
func mapSlice() {
var s []map[string]int
s = make([]map[string]int,5)
for k,v := range s {
fmt.Printf("index:%d val: %v\n",k,v)
}
//要对于slice的index对应的map要做初始化操作,否则会panic
s[0]=make(map[string]int,16)
s[0]["abc"] = 100
for k,v := range s {
fmt.Printf("index:%d val: %v\n",k,v)
}
}
函数
函数的声明和定义
- 定义: 有输入,有输出,用来执行一个指定任务的代码块
func functionName([parametername type]) [return type] {
functionBody
}
分类
- 无参数和返回值的函数
func functionname() {
functionbody
}
- 多返回值
// 多返回值
func Calc(a,b int) (int,int) {
return a+b,a-b
}
func Calc2(a,b int) (sum,sub int) {
sum = a + b
sub = a - b
// 默认会反回所有的返回值
return
}
func main() {
sum,sub := Calc(10,20)
fmt.Println(sum,sub)
}
- 参数分为可变参数(可以不传)和固定参数(必须要传)
func Add(a ...int) int {
//打印可变参数,可变参数其实是个切片
fmt.Printf("func args count %d\n",len(a))
var sum int
for index,arg := range a {
fmt.Printf("arg[%d]=%v\n",index,arg)
sum += arg
}
return sum
}
func main() {
sum := Add(1,2,3)
fmt.Println(sum)
}
- defer语句
作用是为了延迟执行,比如打开文件需要关闭文件句柄,只需要函数结束之后使用difer关闭文件句柄即可,减少多次文件读写需要多次关闭的问题
多个defer语句遵循栈的特征:先进后出
func TestDefer() {
defer fmt.Println("hello world")
defer fmt.Println("nihao!")
fmt.Println("dabaojian")
file,err := os.Open("./a.txt")
if err != nil {
fmt.Println("打开文件失败",err)
return
}
//defer 实战
var buf[4096]byte
n,errs := file.Read(buf[:])
if errs != nil {
fmt.Println("打开文件失败",err)
return
}
// 关闭文件句柄
defer file.Close()
fmt.Printf("read %d byte succ,content: %s\n",n,string(buf[:]))
return
}
常见的内置函数
- close: 用来关闭channel
- len: 用来计算长度
- new: 用来分配内存,主要用于分配值类型;比如int,struct,返回的是指针
- make: 主要用于分配内存或者初始化,主要用于chan,map,slice
- append: 主要用于添加元素到数组,slice中
- panic和recover: 用于错误处理
变量以及作用域
- 全局变量
- 局部变量(函数内部定义)(语句块内定义【if,for】)
- 变量的可见性:首字母小写的话是私有的,首字母大写是public的能够挎包访问
匿名函数
定义: 没有名字的函数
- 结合defer使用(闭包:不含参数的匿名函数)
func TestDefer() {
defer fmt.Println("hello world")
defer fmt.Println("nihao!")
fmt.Println("dabaojian")
file,err := os.Open("./a.txt")
defer func(){
if file !=nil {
file.Close()
}
}()
var buf[4096]byte
n,errs := file.Read(buf[:])
if errs != nil {
fmt.Println("打开文件失败",err)
return
}
fmt.Printf("read %d byte succ,content: %s\n",n,string(buf[:]))
return
}
- 带参数的匿名函数
func TestDefer() {
defer fmt.Println("hello world")
defer fmt.Println("nihao!")
fmt.Println("dabaojian")
file,err := os.Open("./a.txt")
defer func(f *os.File) {
if f != nil {
f.Close()
}
}(file)
var buf[4096]byte
n,errs := file.Read(buf[:])
if errs != nil {
fmt.Println("打开文件失败",err)
return
}
fmt.Printf("read %d byte succ,content: %s\n",n,string(buf[:]))
return
}
- 函数作为一个参数
- 重要点: 可变参数其实是个切片,第二次提示
func calc(op func(args ...int)int,op_args ...int) int{
result :=op(op_args...)
fmt.Printf("result %d\n",result)
return result
}
func main() {
calc(func(args ...int)int{
var sum int
for i:=0;i<len(args);i++{
sum += args[i]
}
return sum
},1,2,3,4,5)
calc(func(args ...int)int{
var sub int
for i:=0;i<len(args);i++{
sub -= args[i]
}
return sub
},1,2,3,4,5)
}
- 可变参数例子(2)
func add(args ...int)int{
var sum int
for i:=0;i<len(args);i++{
// 再一次证明可变参数是切片
sum += args[i]
}
return sum
}
func main() {
fmt.Printf("输出:%d\n",add(1,2,3,4,5))
}
- 闭包: 一个函数与其相关的引用环境组合而成的实体(比较抽象),匿名函数引用到一个外部的变量
当闭包被重新赋值调用的时候,会重新开始计算
func Adder() func(int) int {
//闭包,定义外部的x,默认是0
var x int
return func(d int) int {
// 引用外部环境的x,并对此做操作,从而改变外部的x的值
x += d
return x
}
}
func main() {
var f = Adder()
fmt.Println(f(1))
fmt.Println(f(20))
fmt.Println(f(300))
fmt.Println("========分割线======")
// 接下来就验证了闭包重新调用会将外部引用的因素还原
var f2 = Adder()
fmt.Println(f2(1))
fmt.Println(f2(20))
fmt.Println(f2(300))
}
闭包小练习
- 累加
// base 作为全局变量
func add(base int) func(int) int {
return func(i int) int {
base += i
return base
}
}
func main() {
tmp1 := add(0)
fmt.Println(tmp1(1),tmp1(2))
tmp2 := add(100)
fmt.Println(tmp2(1),tmp2(2))
}
- 后缀添加例子
func makeSuffixFunc(suffix string) func(string) string {
return func(name string) string {
//判断名称是否包含后缀
if !strings.HasSuffix(name,suffix) {
return name+suffix
}
return name
}
}
func main() {
func1 := makeSuffixFunc(".bmp")
func2 := makeSuffixFunc(".jpg")
fmt.Println(func1("test"))
fmt.Println(func2("test"))
}
- 计算覆盖
func calcs(base int) (func(int) int,func(int)int) {
add := func(i int) int{
base += i
return base
}
sub := func(i int) int{
base -= i
return base
}
return add,sub
}
func main() {
f1,f2 := calcs(10)
fmt.Println(f1(1),f2(2))
fmt.Println(f1(3),f2(4))
fmt.Println(f1(5),f2(6))
fmt.Println(f1(7),f2(8))
}
有疑问加站长微信联系(非本文作者)