• Go切片


    切片

    声明切片

    var name []T

    • T 代表切片类型对应的元素类型

    切片默认指向一段连续内存区域,可以是数组,也可以是数组本身

    从连续区域生成切片是常规的操作,格式:

    slice [开始位置:结束位置]
    
    var a = [3]int{1,2,3}
    b := a[1,2]
    

    从数据或切片生成的新的切片具有以下特性:

    • 取出的元素数量为:结束位置-起始位置;
    • 取出元素不包括结束位置对应的索引,切片最后一个元素你用slice[len(slice)]获取;
    • 当缺省开始位置时,表示从连续区域开头到结束位置;
    • 当缺生结束位置时,表示从开始位置到整个连续区域末尾;
    • 两者同时缺省时,与切片本身等效;
    • 两者同时为0,等效于空切片,一般用于切片复位;
    • 超界会报错

    重置切片,清空拥有的元素

    a :=[]int{1,2,3}
    fmt.Println(a[0:0)
    //[]
    

    make()函数制造切片

    make([]T,len,cap)
    
    • len : 长度
    • cap : 容量
    • 切片不一定必须经过make() 函数才能使用。生成切片、声明后使用append()函数均可以正常使用切片。

    append动态添加元素

    每个切片会指向一片内存空间,这片空间容纳容量的元素,超过容量,切片就会"扩容"。"扩容"操作往往发生在append调用时。

    var car []string
    car = append(car,"Old Driver")
    
    //添加多个元素
    car = append(car,"ice","Monk")
    
    //添加切片
    team := []string{"Pig","Flyingcake","Chicken"}
    car = append(car,team...)
    
    fmt.PrintLn(car)
    

    切片的增长规律,参考:https://www.jianshu.com/p/54be5b08a21c

    简单的理解如下:

    a. 当需要的容量超过原切片容量的两倍时,会使用需要的容量作为新容量。

    b. 当原切片长度小于1024时,新切片的容量会直接翻倍。而当原切片的容量大于等于1024时,会反复地增加25%,直到新容量超过所需要的容量。

    切片底层是数组逻辑的实现,切片在扩充容量时,会产生一个新数组

    为了避免因为切片是否发生扩容的问题导致bug,最好的处理办法还是在必要时使用 copy 来复制数据,保证得到一个新的切片,以避免后续操作带来预料之外的副作用

    复制切片元素到另一个切片

    copy()函数,可以迅速的讲一个切片的数据复制到另一个切片空间中。

    copy( dest Slice, src Slice []T ) int
    

    copy 的返回值表示实际发生复制的元素个数。

    package main
    
    import "fmt"
    
    func main()  {
    
    	//引用切片数据
    	ref_Data := src_Data
    
    	//预分配足够多的元素切片
    	copy_data := make([]int,element_Count)
    	//将数据赋值到新的切片空间中
    	copy(copy_data,src_Data)
    
    	//修改原始数据的第一个元素
    	src_Data[0] = 999
    
    	//打印引用切片的第一个元素
    	fmt.Println(ref_Data[0])
    
    	//打印复制切牌呢的第一个和最后一个元素
    	fmt.Println(copy_data[0],copy_data[element_Count-1])
    
    	// 复制原始数据从4到6(不包含)
        copy(copy_data,src_Data[4:6])
    
    	for i :=0; i < 5; i++ {
    		fmt.Printf("%d ",copy_data[i])
    	}
    }
    
    
    /*
      999
      0 999
      4 5 2 3 4
      */
    

    复制空间 独立空间。

    从切片中删除元素

    GO并没有对删除切片元素提供的专门语法,需要使用切片本身的特性来删除元素。

    package main
    
    import "fmt"
    
    func main()  {
    
        seq := []string{"a", "b", "c", "d", "e"}
        //指定删除位置
        index := 2
    
    	//查看删除位置之前的元素和之后的元素
    	fmt.Println(seq[:index], seq[index+1:])
    
    	//将删除点前后的元素连接起来
    	seq = append(seq[:index], seq[index+1:]...)
    
    	fmt.Println(seq)
    }	
    

    Go中删除元素的本质:是以删除元素为分界点,将前后两个部分的内存重新连接起来。

    Array类型的值作为函数参数

    作为参数传进函数时,传递的是数组的原始值拷贝,此时在函数内部是无法更新该数组的:

    // 数组使用值拷贝传参
    func main() {
    	x := [3]int{1,2,3}
    
    	func(arr [3]int) {
    		arr[0] = 7
    		fmt.Println(arr)	// [7 2 3]
    	}(x)
    	fmt.Println(x)			// [1 2 3]	// 并不是你以为的 [7 2 3]
    }
    

    如果想修改参数数组:

    • 直接传递指向这个数组的指针类型:
    // 传址会修改原数据
    func main() {
    	x := [3]int{1,2,3}
    
    	func(arr *[3]int) {
    		(*arr)[0] = 7	
    		fmt.Println(arr)	// &[7 2 3]
    	}(&x)
    	fmt.Println(x)	// [7 2 3]
    }
    
    • 直接使用 slice:即使函数内部得到的是 slice 的值拷贝,但依旧会更新 slice 的原始数据(底层 array)
    // 会修改 slice 的底层 array,从而修改 slice
    func main() {
    	x := []int{1, 2, 3}
    	func(arr []int) {
    		arr[0] = 7
    		fmt.Println(x)	// [7 2 3]
    	}(x)
    	fmt.Println(x)	// [7 2 3]
    }
    
  • 相关阅读:
    实现一个基本的静态文件服务的Web服务器
    Http模块
    Java环境
    HelloWorld
    HTTP(s)
    第16条:复合优先于继承
    Tomcat配置https
    第15条:使可变性最小化
    第14条:在公有类中使用访问 方法而非公有域
    第13条:使类和成员的可访问性最小化
  • 原文地址:https://www.cnblogs.com/followyou/p/12349883.html
Copyright © 2020-2023  润新知