zoukankan      html  css  js  c++  java
  • golang高级学习笔记

    1. 在以字符串作为参数传递给fmt.Println函数时,字符串的内容并没有被复制

    ——传递的仅仅是字符串的地址和⻓度(字符串的结构在 reflect.StringHeader  中定义)。在Go语⾔

    中,函数参数都是以复制的⽅式(不⽀持以引⽤的⽅式)传递(⽐较特殊的是,Go语⾔闭包函数对外部

    变量是以引⽤的⽅式使⽤)

    2.字符

    字符串的元素不可修改,是⼀个只读的字节数组,

    example:

    func main() {
    //查询Unicode字符串长度用utf8.RuneCountInString()函数,ASCII字符用len()
    str1:="君のことが大好きです、"
    str2:="这是中文"
    n1:=utf8.RuneCountInString(str1)
    n2:=utf8.RuneCountInString(str2)
    fmt.Println(n1,n2)
    //bianli_ASCII()//乱码了,
    bianli_Unicode()
      
      
      for i, c := range []byte("世界abc") {
       fmt.Println(i, c)//仅能成功遍历ascii码
      }
    }
    func bianli_ASCII(){
    theme:="狙击 start"
    for i:=0;i<len(theme);i++{
    fmt.Printf("ASCII: %c %d ",theme[i],theme[i])
    }
    }
    func bianli_Unicode(){
    theme:="狙击 start"
    for _,s:=range theme{
    fmt.Printf("Unicode: %c %d ",s,s)
    }
    }
    3.切片

    ⽤ copy 和 append 组合可以避免创建中间的临时切⽚,同样是完成添加元素的操作:
    a = append(a, 0) // 切⽚扩展1个空间
    copy(a[i+1:], a[i:]) // a[i:]向后移动1个位置
    a[i] = x // 设置新添加的元素
    第⼀句 append ⽤于扩展切⽚的⻓度,为要插⼊的元素留出空间。第⼆句 copy 操作将要插⼊位置开始
    之后的元素向后挪动⼀个位置。第三句真实地将新添加的元素赋值到对应的位置。操作语句虽然冗⻓
    了⼀点,但是相⽐前⾯的⽅法,可以减少中间创建的临时切⽚。

    3.1

    删除切⽚元素
    根据要删除元素的位置有三种情况:从开头位置删除,从中间位置删除,从尾部删除。其中删除切⽚
    尾部的元素最快:
    a = []int{1, 2, 3}
    a = a[:len(a)-1] // 删除尾部1个元素
    a = a[:len(a)-N] // 删除尾部N个元素

    3.1.1

    删除开头的元素也可以不移动数据指针,但是将后⾯的数据向开头移动。可以⽤ append 原地完成(所
    谓原地完成是指在原有的切⽚数据对应的内存区间内完成,不会导致内存空间结构的变化):
    a = []int{1, 2, 3}
    a = append(a[:0], a[1:]...) // 删除开头1个元素
    a = append(a[:0], a[N:]...) // 删除开头N个元素
    也可以⽤ copy 完成删除开头的元素:
    a = []int{1, 2, 3}
    a = a[:copy(a, a[1:])] // 删除开头1个元素
    a = a[:copy(a, a[N:])] // 删除开头N个元素

    3.2

    在判断⼀个切⽚是否为空时,⼀般
    通过 len 获取切⽚的⻓度来判断,⼀般很少将切⽚和 nil 值做直接的⽐较。

    TrimSpace 函数⽤于删除 []byte 中的空格。函数实现利⽤了0⻓切⽚的特性,实现⾼效⽽
    且简洁。
    func TrimSpace(s []byte) []byte {
    b := s[:0]
    for _, x := range s {
    if x != ' ' {
    b = append(b, x)
    }
    }
    return b
    }

    
    

    类似的问题,在删除切⽚元素时可能会遇到。假设切⽚⾥存放的是指针对象,那么下⾯删除末尾的元
    素后,被删除的元素依然被切⽚底层数组引⽤,从⽽导致不能及时被⾃动垃圾回收器回收(这要依赖
    回收器的实现⽅式):
    var a []*int{ ... }
    a = a[:len(a)-1] // 被删除的最后⼀个元素依然被引⽤, 可能导致GC操作被阻碍

    将需要⾃动内存回收的元素设置为 nil ,保证⾃动回收器可以发现需要回收的对象,
    然后再进⾏切⽚的删除操作:
    var a []*int{ ... }
    a[len(a)-1] = nil // GC回收最后⼀个元素内存
    a = a[:len(a)-1] // 从切⽚删除最后⼀个元素
    当然,如果切⽚存在的周期很短的话,可以不⽤刻意处理这个问题。因为如果切⽚本身已经可以被GC
    回收的话,切⽚对应的每个元素⾃然也就是可以被回收的了。

    通过两种⽅法将 []float64  类型的切⽚转换为 []int  类型的切⽚:

    三个索引的切片

    1. 第三个索引可以限定容量。对于slice[i:j:k],长度=j-i,容量=k-i

    2. 在创建切片时设置切片的容量和长度一样,可以强制让新切片的第一个append操作创建新的底层数组,与原有的底层数组分类。保持数组的简洁,更加的安全。

      • a. 若不限定分片的容量,直接append的话可能会覆盖底层数组,从而影响到其他切片,出现奇怪的bug
      func main(){
       b := []int{1, 2, 3, 4, 5, 6}
       c := b[: 2]
       c = append(c, 7)
       fmt.Println(b)
       fmt.Println(c)
      }
      
      ----------------------
      //b切片被c影响
      [1 2 7 4 5 6]
      [1 2 7]
      
      • b. 在使用切片时限定容量可以避免上述情况
      func main(){
       b := []int{1, 2, 3, 4, 5, 6}
       c := b[: 2:2]
       c = append(c, 7)
       fmt.Println(b)
       fmt.Println(c)
      }
      
      ------------------
      //在使用切片时限定容量,c切片append时开辟了新的数组,不影响原数组上的切片
      [1 2 3 4 5 6]
      [1 2 7]
      


    4.函数、方法、接口

    当可变参数是⼀个空接⼝类型时,调⽤者是否解包可变参数会导致不同的结果:
    func main() {
    var a = []interface{}{123, "abc"}
    Print(a...) // 123 abc
    Print(a) // [123 abc]
    }
    func Print(a ...interface{}) {
    fmt.Println(a...)
    }
    第⼀个 Print 调⽤时传⼊的参数是 a... ,等价于直接调⽤ Print(123, "abc") 。第⼆个 Print 调⽤
    传⼊的是未解包的 a ,等价于直接调⽤ Print([]interface{}{123, "abc"}) 。

    如果返回值命名了,可以通过名字来修改返回值,也可以通过 defer 语句在 return 语句之后修改返
    回值:
    func Inc() (v int) {
    defer func(){ v++ } ()
    return 42
    }
    其中 defer 语句延迟执⾏了⼀个匿名函数,因为这个匿名函数捕获了外部函数的局部变量 v ,这种函
    数我们⼀般叫闭包。闭包对捕获的外部变量并不是传值⽅式访问,⽽是以引⽤的⽅式访问。

    函数的递归调用
    //斐波那契数列实现,炫啊
    /*1 2 3 4 5 6 7 8 9 10 11 12
    1 1 2 3 5 8 13 21 34 55 89 144
    */
    func fibonacci(n int)int{
    if n==1||n==2{
    return 1
    }
    return fibonacci(n-2)+fibonacci(n-1)
    }
    f:=fibonacci(a)
    fmt.Printf("斐波那契数列第%d项是%d",a,f)

    //求1+2+3+...n项和
    func getsum(n int)int {
    if n==1{
    return 1
    }
    return getsum(n-1)+n
    }
    将⽅法还原为普通类型的函数:
    var ReadFile = (*File).Read
    ReadFile(f, 0, data)


    老婆董香镇楼。

  • 相关阅读:
    RabbitMQ消息队列
    集群概念
    重新学习CSS,认识CSS3中的属性
    计算机网络中,路由器和交换机的区别
    微信小程序中,如何点击链接跳转到外部网页
    微信小程序中,如何实现显示,隐藏密码的功能
    Vue 中引入echarts
    解决Ubuntu(linux)系统中PHP的curl函数无法使用的问题
    数据通信的基本知识
    计算机网络的性能
  • 原文地址:https://www.cnblogs.com/wddx5/p/12286924.html
Copyright © 2011-2022 走看看