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))

}