golang Golang并发切片示例

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang Golang并发切片示例相关的知识,希望对你有一定的参考价值。

package main

import (
	"fmt"
	"sort"
	"sync"
)

type ConcurSlice struct {
	sync.Mutex
	items []int
}

// Append appends an element to the end of ConcurSlice
func (cs *ConcurSlice) Append(item int) {
	cs.Lock()
	defer cs.Unlock()
	cs.items = append(cs.items, item)
}

// Pop pops and returns last element from ConcurSlice
func (cs *ConcurSlice) Pop() int {
	cs.Lock()
	defer cs.Unlock()
	last := cs.items[len(cs.items)-1]
	cs.items = cs.items[:len(cs.items)-1]
	return last
}

// Len returns length of ConcurSlice
func (cs *ConcurSlice) Len() int {
	cs.Lock()
	defer cs.Unlock()
	return len(cs.items)
}

// Less returns a boolean result of comparing two items in ConcurSlice
func (cs *ConcurSlice) Less(i, j int) bool {
	cs.Lock()
	defer cs.Unlock()
	return cs.items[i] < cs.items[j]
}

// Swap changes positions of two items in ConcurSlice
func (cs *ConcurSlice) Swap(i, j int) {
	cs.Lock()
	defer cs.Unlock()
	cs.items[i], cs.items[j] = cs.items[j], cs.items[i]
}

// Items returns a copy of items in ConcurSlice
func (cs *ConcurSlice) Items() []int {
	cs.Lock()
	defer cs.Unlock()
	return cs.items
}

// Iter returns an Iterator channel over items in ConcurSlice
func (cs *ConcurSlice) Iter() <-chan int {
	var c = make(chan int)
	cs.Lock()
	defer cs.Unlock()
	go func() {
		cs.Lock()
		defer cs.Unlock()
		for _, value := range cs.items {
			c <- value
		}
		close(c)
	}()
	return c
}

// NewCS returns a new instance of ConcurSlice
func NewCS(initial []int) *ConcurSlice {
	newSlc := &ConcurSlice{
		items: initial,
	}
	return newSlc
}

func main() {
	s := NewCS([]int{9, 6, 5, 8, 7})
	fmt.Printf("Items[1]: %v\n", s.Items()) // [9 6 5 8 7]
	sort.Sort(s)                            // [5 6 7 8 9]
	s.Append(10)                            // [5 6 7 8 9 10]
	fmt.Printf("Items[2]: %v\n", s.Items())
	s.Pop()
	fmt.Printf("Items[3]: %v\n", s.Items()) // [5 6 7 8 9]

	// range over iterator
	for value := range s.Iter() {
		fmt.Println(value)
	}
}

Golang:切片的声明初始化以及操作示例,详解概括

Golang基础学习项目地址:https://github.com/LeoLeeWithWarmPants/golangStudyhttps://github.com/LeoLeeWithWarmPants/golangStudy

概述

slice本质上是一个数据结构(struct结构体)。

  • 切片是数组的一个引用,即切片的底层是一个数组,所以切片是一个引用类型。

  • 切片的长度是可以变化,由于其支持扩容(类似于Java的List),可以理解切片为一个“长度动态变化的数组”。

    • 需要注意的是,支持扩容并不代表可以越界操作

    • 扩容后,底层创建并引用了新的数组,将数据赋值到新的数组

  • 可以使用数组或者是make两种方式来初始化一个切片。

    • 需要注意的时make也是会创建底层数组的。数组的长度为make设置的capcity,数组元素的值为数组类型对应的默认值。

  • 切片可以被继续切片。产生的新切片和原切片公用同一个底层数组,修改新的切片会影响原切片

slice变量声明、初始化后,其内存空间内包含:

  • slice首个元素的地址(该元素对应原始数组的某个元素)

  • slice的长度

  • 容量(slice底层数组的长度)

在使用数组初始化切片的时候,一定要注意数组是值传递,还是作为了切片的底层数组通过make创建的切片顶层的数组只能通过切片来操作,该数组没有其他的引用

示例

package main

import (
	"errors"
	"fmt"
)

const length int = 5

var intArray = [length]int1, 3, 5, 7, 9

//从一个数组中获取一个切片
//通过make创建的切片顶层的数组只能通过切片来操作,该数组没有其他的引用
func getSliceFromArray(array [length]int) []int 
	slice := array[1:3] // 1:3 代表从数组下标为1的元素开始取值,到下标为3的元素位置,不包含3。如果从0开始引用数组,也可以省略冒号前的0(如 array[:3]),反之同理。
	return slice


//通过make创建一个切片
func getSliceByMake() []int 
	var slice3 []int = make([]int, 4, 8)
	fmt.Printf("slice3 length=%d, capcity=%d\\n", len(slice3), cap(slice3))
	return slice3


//创建切片时,初始化切片引用的数组
func getSliceByInitArray() []int 
	var slice4 []int = []int1, 3, 5, 7, 9
	fmt.Printf("slice4 length=%d, capcity=%d\\n", len(slice4), cap(slice4))
	return slice4


//对切片进行切片,从一个切片产生一个新的切片
func getSliceFromSlice(slice []int) []int 
	return slice[0:2]


//切片的遍历
func sliceTraverseByFori(slice []int) 
	fmt.Println("sliceTraverseByFori executing...")
	for i := 0; i < len(slice); i++ 
		if i == len(slice)-1 
			fmt.Printf("slice[%d]:%d \\n", i, slice[i])
		 else 
			fmt.Printf("slice[%d]:%d ", i, slice[i])
		
	
	slice[0] = 2

func sliceTraverseByForRange(slice []int) 
	fmt.Println("sliceTraverseByForRange executing...")
	for idx, element := range slice 
		if idx == len(slice)-1 
			fmt.Printf("slice[%d]:%d \\n", idx, element)
		 else 
			fmt.Printf("slice[%d]:%d ", idx, element)
		
	


//测试切片扩容
func testDilatationByAppend(slice1 []int, slice2 []int, args ...int) []int 
	if slice1 == nil 
		panic(errors.New("被扩容的切片不能为空"))
	
	if slice2 != nil 
		slice1 = append(slice1, slice2...)
	
	if args != nil && len(args) > 0 
		slice1 = append(slice1, args...)
	
	return slice1


func main() 
	//从一个数组中获取一个切片
	slice1 := getSliceFromArray(intArray)
	fmt.Printf("slice1 from an array, slice1=%v,length=%d,capacity=%d\\n", slice1, len(slice1), cap(slice1))
	fmt.Printf("intArray memory address:%p\\n", &intArray)
	fmt.Printf("intArray[1] memory address:%p\\n", &intArray[1])
	fmt.Printf("slice1 memory address:%p\\n", &slice1)
	fmt.Printf("slice1[0]=%d, slice1[0] memory address:%p\\n", slice1[0], &slice1[0]) // slice1[0] == intArray[1] == 3

	//由于getSliceFromArray函数中声明并初始化了slice1,intArray是基本类型,通过值传递进入了getSliceFromArray函数,所以修改slice1的值并不影响intArray
	slice1[0] = 2
	fmt.Printf("after slice1 changed,slice1=%v\\n", slice1)
	fmt.Printf("after slice1 changed,intArray=%v\\n", intArray)
	//当slice2和intArray2处在同一作用域时,slice2中的元素地址指向了intArray2中的元素,修改slice2的元素值等于修改intArray2中的元素
	intArray2 := [length]int0, 2, 4, 6, 8
	slice2 := intArray2[1:3]
	fmt.Printf("slice2=%v\\n", slice2)
	slice2[0] = 28
	fmt.Printf("after slice2 changed,slice2=%v\\n", slice2)
	fmt.Printf("after slice2 changed,intArray2=%v\\n", intArray2)

	//通过make创建切片
	slice3 := getSliceByMake()
	fmt.Printf("slice3:%v, slice3 memory address:%p\\n", slice3, &slice3)

	//创建切片时,初始化切片引用的数组
	slice4 := getSliceByInitArray()
	fmt.Printf("slice4=%v\\n", slice4)

	//切片fori遍历
	sliceTraverseByFori(slice4)
	sliceTraverseByFori(slice4) //由于切片是引用传递,所以方法内部对切片的变动,将会影响源数据
	sliceTraverseByForRange(slice4)

	//对切片进行切片,从一个切片产生一个新的切片
	fmt.Printf("slice4=%v\\n", slice4)
	slice5 := getSliceFromSlice(slice4)
	fmt.Printf("slice5=%v\\n", slice5)
	slice5[0] = 33
	fmt.Printf("after slice5 changed, slice4=%v\\n", slice4) //说明切片slice4产生的切片slice5,slice4和slice5公用一个底层的数组

	//切片扩容测试
	intArray3 := [...]int1, 2
	slice6 := intArray3[:]
	fmt.Printf("slice6=%v, length=%d, capcity=%d, address=%p\\n", slice6, len(slice6), cap(slice6), &slice6)
	slice7 := []int3, 4, 5
	slice6 = testDilatationByAppend(slice6, slice7)
	//由此可以看到切片在append元素之后,capcity增加了,虽然切片的地址没有变化,但是由数组声明后长度不可变可知,底层的数据肯定不是intArray3了
	fmt.Printf("slice6=%v, length=%d, capcity=%d, address=%p\\n", slice6, len(slice6), cap(slice6), &slice6)

	//切片的拷贝
	slice8 := []int1, 2, 3
	slice9 := make([]int, 6)
	copyLength := copy(slice9, slice8)
	fmt.Printf("copyLength=%d\\n", copyLength)
	fmt.Printf("slice8=%v\\n", slice8)
	fmt.Printf("slice9=%v\\n", slice9)

以上是关于golang Golang并发切片示例的主要内容,如果未能解决你的问题,请参考以下文章

Golang:切片的声明初始化以及操作示例,详解概括

Golang:切片的声明初始化以及操作示例,详解概括

Golang SWIG 示例 2:切片边界超出范围恐慌

Golang按名称排序切片[关闭]

Golang 函数传参使用切片而不使用数组为什么?

Golang 函数传参使用切片而不使用数组为什么?