GO语言学习笔记4——特色的部分

内置函数

  • close

    • 主要用来关闭channel
  • len

    • 用来求长度
    • string,array,slice,map,channel
  • new

    • 用来分配内存,主要用来分配值类型,比如int、struct
    • 返回的是指针
  • make

    • make不仅是分配内存,而且进行了初始化
    • 用来分配内存,主要用来分配引用类型,比如chan,map,slice
    • 返回的就是实体,不是指针
    • s := make([]int,10)
      • make不仅分配了内存,而且进行了初始化
  • append

    • 用来追加元素到数组,slice中

    • 1
      2
      3
      var a[]int
      a = append(a,10,20,11)
      a = append(a,a...) //将a 追加到 a后
      • …是可以将slice展开
  • panic和recover

    • 用来做错误处理

闭包

一个函数和与其相关的引用环境组会而成的实体。

这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import "fmt"
func Adder() func(int) int {
var x int
return func(d int) int {
x += d
return x
}
}
func main(){
f:= Adder()
fmt.Println(f(1))
fmt.Println(f(100))
fmt.Println(f(1000))
}

“斐波那契数列”闭包:

1
2
3
4
5
6
7
8
9
10
11
12
func fib() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
调用如下
f00 := fib()
fmt.Println(f00(), f00(), f00(), f00(), f00())
输出结果是:1 1 2 3 5

我们先对闭包分3种场景:

  • 闭包里没有引用环境(变量生命周期很短,调用完即释放)
  • 闭包里引用全局变量(变量生命周期就是全局变量生命周期)
  • 闭包里引用局部变量(变量生命周期长,调用完不释放,下次调用会继续引用)

3种场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var y int
// 第一种场景
func fib01() func() int {
return func() int {
a, b := 0, 1
a, b = b, a+b
return a
}
}
// 第二种场景
func fib00() func() int {
return func() int {
y++
return y
}
}
// 第三种场景
func fib3(x int) func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
x++
return a+x
}
}

闭包是让自由变量和函数绑定起来,这样有点像C++中类的成员变量和类成员函数一样。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main
import(
"fmt"
"strings"
)
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"))
}

关键看闭包函数和那个自变量绑定

数组

  • 数组:同一种数据类型的固定长度序列。

  • 数组是值类型

  • 定义:

    • var a [len]int
    • var b = [...]int{1,2,3,4,5}
  • 长度是数组类型的一部分,因此var a[5]int 和var b[10]int 是不同的类型

  • 访问越界会panic

  • 数组是值类型,因此改变数组的副本值,不会改变本身的值

    • 1
      2
      arr2 := arr1
      arr2[2] = 10
  • 想要传递到函数里并能改变数组里的内容,传指针进去

    • 1
      2
      3
      func test(arr *[5]int){
      (*arr)[0] = 100
      }

切片

  • 切片

    • 切片是数组的一个引用,因此切片是引用类型
  • 切片的长度可以改变,因此,切片是一个可变的数组

  • 切片遍历方式和数组一样,并且一样用len()求长度

  • cap可以求出slice最大容量

  • 切片的定义:

    • var xxx []类型
  • 切片的初始化

    • var slice []int = arr[start:end]
  • 通过make创建切片并初始化

    • 1
      2
      3
      var slice []type = make([]typelen)
      slice := make([]type,len)
      slice := make([]type, len, cap)
  • append追加元素

    • slice = append(slice,10)
  • 注意:

    • 当以数组作为切片的初始化列表时,改变数组或者切片,两者会相互影响

    • 除非切片append超过数组元素后,会开辟一片新内存,复制过去,在那之前,用来初始化切片的数组和切片某种程度上是“连体的”。

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      func main() {
      var a [5]int = [...]int{1, 2, 3, 4, 5}
      s := a[1:]
      s[1] = 100
      fmt.Println(a)
      a[3] = 666
      fmt.Println(a)
      fmt.Println(s)
      }
  • cap的扩容是每次翻倍

  • 切片的拷贝

    • 内置函数copy直接搞定,不需要自己写循环

    • 1
      2
      3
      s1 := []int{1,2,3,4,5}
      s2 := make([]int,10)
      copy(s2,s1)
  • string底层是一个byte数组,因此,可以用切片操作

  • 但是string本身是不可变的,因此改变string中的字符,需要:

    • 1
      2
      3
      4
      str := “hello"
      s := []byte(str)//s := []rune(str) 用rune可以处理中文
      s[0] = 'y'
      str = string(s)

排序

  • 对整数进行排序

  • import “sort”

  • 数组是一个值类型的,要排序需要传切片类型进去

    • 这里利用到数组初始化切片时的“连体效果”

    • 1
      2
      3
      4
      5
      func testIntSort(){
      var a = [...]int{1,100,76,3,2}
      sort.Ints(a[:])
      fmt.Println(a)
      }
  • 对字符串,对float都有专门的排序函数

  • 排序后查找

    • sort.SearchInts
    • 返回的是排序后的下标

map

  • 声明

    • var mymap map[keytype]valuetype
  • 声明是不分配内存的,初始化需要make

  • 如果只证明了没有初始化就直接使用map,会panic

    • 有时候你不确定某个map是否是初始化了。为了防止panic,可以用之前先判断下:

    • 1
      2
      3
      if (mymap==nil){
      初始化 mymap
      }
  • 初始化

    • 1
      2
      var mymap map[keytype]valuetype
      mymap = make(map[keytype]valuetype,cap)
    • mymap := make(map[keytype]valuetype,cap)

  • 插入和更新

    • a[“xxx”] = “hello”
  • 查找

    • val,ok := a[“xxx”]
  • 遍历

    • 1
      2
      3
      for k,v := range a{
      fmt.Println(k,v)
      }
  • 删除

    • delete(a,”xxx”)
  • 长度

    • len(a)
  • map 本身 key是无序的,如果想有序遍历可以自行处理

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      var keys[]int
      for k,_:= range mymap{
      keys.append(keys,k)
      }
      sort.Ints(keys)
      for _,v := range keys{
      fmt.Println(v,mymap[v])
      }

本文标题:GO语言学习笔记4——特色的部分

文章作者:Yang Shuai

发布时间:2019年06月09日 - 22:06

最后更新:2019年06月09日 - 22:06

原始链接:https://ysbbswork.github.io/2019/06/09/GO语言学习笔记4——特色的部分/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!