1 Go语言中的切片是什么?
切片:动态数组,比如Java当中的ArrayList,Python中的list以及c++当中的vector,这些就是动态数组
1.1 何为动态数组
动态数组,字如其名,动态的数组,可以无限添加数组的元素,会进行自动扩容
2 Go中的切片有哪些特征?
2.1 先看Go中的源码
type slice struct {
array unsafe.Pointer // 指针类型,是一个指针
len int // 动态数组长度
cap int // 动态数组容量
}
// 动态数组长度是指初始化几个默认值为0的数据
// 容量指的是切片到了多少个元素需要进行扩容
// 向切片的末尾添加元素
func append(slice []Type, elems ...Type) []Type
思考:这个array是什么类型的指针-------数组
2.2 这里可以类比Java中的ArrayList进行思考
下面来自ArrayList的源码
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 数组的长度
*/
private int size;
/**
* ArrayList的底层数组
*/
transient Object[] elementData;
/**
* 传入一个动态数组的初始容量,对动态数组的底层数组进行初始化
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 对数组进行添加数据
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/*
* 确定最小需要扩容的值,有可能是0
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
/*
* 如果原来是空的,就先分配长度为默认值的数组
*/
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 确定容量够存放添加的元素
ensureExplicitCapacity(minCapacity);
}
// 进行扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 扩容的方法
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
2.3 分析
-
Go中的array其实就是Java中的elementData,表示底层的数组
-
Go中的append()类似于Java中的add()方法
-
Java中的size就是Go中的len,表示当前动态数组的元素个数
-
Java中的DEFAILT_CAPACITY以及构造方法中传入的参数capacity就是Go中的cap,表示动态数组容量
3 底层原理
Go和Java当中都是操作一个数组的指针,对其进行添加元素。如果
添加的元素超出了原来的容量,就会进行扩容,而扩容的方式是新
建一个数组,然后让这个数组作为动态数组的底层数组。
注意点:切片的len决定了底层数组可以被访问的最后位置
3.1 具体问题
func main() {
arr:=make([]int,3,8)
//创建一个切片
arr = append(arr, 12)
// 如果不需要扩容就是在底层数组可以被访问的最后位置,修改0为追加的值,不需要扩容,修改底层数组就可以了,所以原切片里的数组指针的值也会改变
fmt.Println(arr)
// 将切片作为参数传递
dealArray(arr)
fmt.Println(arr)
//
}
//golang中的传值都是值传递
func dealArray(arr []int) {
//arr = append(arr, 12)
//如果不需要扩容的话,同上,但是原数组的len和cap是不会修改的,因为我们将原切片的len和cap加一后给了一个新的由原切片复制得到的arr,不是原来的arr,所以这时主函数中的len还是原来的len,没有改变,所以就无法访问到append的那个数
//如果需要扩容的话就会创建一个新的数组指针放到切片结构体对象的属性当中,这时,就不会对原切片进行修改了
}