切片:动态数组,底层也是数组
切片的结构
type slice struct {
array unsafe.Pointer //一个指向数组的指针
len int //当前容量
cap int //最大容量
}
var a []string
var b = []string{}
c := []string{}
d := new([]string)
e := make([]string, 0)
说明 | address | == nil | reflect.DeepEqual( x , nil) | |
---|---|---|---|---|
a | 声明一个切片 | 0x0 | true | true |
b | 声明并赋值 | 0xc000056de0 | false | false |
c | 声明并赋值 简化操作 | 0xc000056de0 | false | false |
nil 切片
只是做了定义,在内存上并没有存在的区域。只是告诉系统我要用这个a ,其它的人不能用了,并没说明 a 要放在内存的那块区域,也就是占用了变量名称而已。
空切片
不仅仅声明了变量,占用了这个变量名,而且还在内存上有相对应的地址
new
new 只分配内存,这样就在内存上有了记录,不在是nil,
返回的是这个变量的指针,指针指向的就是在内存中的位置
make
make 只能用于 slice、map 和 channel 的初始化,
初始化过了,在内存上也有相对应的地址,不能为nil
返回的是这个变量的实例
DeepEqual
// DeepEqual reports whether x and y are ``deeply equal,'' defined as follows.
// Two values of identical type are deeply equal if one of the following cases applies.
// Values of distinct types are never deeply equal.
DeepEqual 比较 x 和 y 是否“深度相等”,定义如下。如果以下情况之一适用,则两个相同类型的值非常相等。不同类型的值永远不会完全相等。
// Array values are deeply equal when their corresponding elements are deeply equal.
数组中的元素都一样的话,那么这个数组就是相等的
// Struct values are deeply equal if their corresponding fields,
// both exported and unexported, are deeply equal.
结构体的值、字段、作用域都一样的话,那么这两个结构体相等
//
// Func values are deeply equal if both are nil; otherwise they are not deeply equal.
//
// Interface values are deeply equal if they hold deeply equal concrete values.
// Map values are deeply equal when all of the following are true:
// they are both nil or both non-nil, they have the same length,
// and either they are the same map object or their corresponding keys
// (matched using Go equality) map to deeply equal values.
map 里面的key 、value 都相等的时候,才会相等
//
// Pointer values are deeply equal if they are equal using Go's == operator
// or if they point to deeply equal values.
两个指针指向同一个值才会相等
//
// Slice values are deeply equal when all of the following are true:
满足以下条件时,切片才能相等:
// they are both nil or both non-nil,
都为nil 时相等
they have the same length, and either they point to the same initial entry of the same underlying array (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal.
长度相等,切片的首地址相等,切片里面的元素相等,
// Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil))
// are not deeply equal.
nil 切片 和有个值是nil 的切片不相等
//
// Other values - numbers, bools, strings, and channels - are deeply equal
// if they are equal using Go's == operator.
其它数据类型的值, 如果== 成立,这个也相等
//
// In general DeepEqual is a recursive relaxation of Go's == operator.
DeepEqual 是递归进行了==比较
// However, this idea is impossible to implement without some inconsistency.
// Specifically, it is possible for a value to be unequal to itself,
特殊情况下,一个变量可能不等自己本身
// either because it is of func type (uncomparable in general)
// or because it is a floating-point NaN value (not equal to itself in floating-point comparison),
// or because it is an array, struct, or interface containing
// such a value.
比如 func 、浮点类型(存在NaN)、结构体中出现引用类型的字段(map、array、interface)
// On the other hand, pointer values are always equal to themselves,
// even if they point at or contain such problematic values,
指针的值总是相等的,因为指向的地址一样。就算指向地址的值不相等,感觉比较的是指针的地址
// because they compare equal using Go's == operator, and that
// is a sufficient condition to be deeply equal, regardless of content.
== 操作 是DeepEqual 的前提条件
// DeepEqual has been defined so that the same short-cut applies
// to slices and maps: if x and y are the same slice or the same map,
// they are deeply equal regardless of content.
这个DeepEqual 可以快捷的比较 切片、map
//
// As DeepEqual traverses the data values it may find a cycle. The
// second and subsequent times that DeepEqual compares two pointer
// values that have been compared before, it treats the values as
// equal rather than examining the values to which they point.
// This ensures that DeepEqual terminates.
当 DeepEqual 遍历数据值时,它可能会找到一个递归循环。
DeepEqual 比较之前比较过的两个指针值的第二次和后续比较时,它将值视为相等,而不是检查它们指向的值。
这确保 DeepEqual 终止
func DeepEqual(x, y interface{}) bool {
if x == nil || y == nil {
return x == y // nil 相等
}
v1 := ValueOf(x)
v2 := ValueOf(y)
if v1.Type() != v2.Type() {
return false // 类型不同 不相等
}
return deepValueEqual(v1, v2, make(map[visit]bool))
}
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
// Value is the reflection interface to a Go value.
Value 是一个反射接口
//
// Not all methods apply to all kinds of values. Restrictions,
并没有限制所有的类型的vlaue都实现了所有的方法,
// if any, are noted in the documentation for each method.
如果有限制,请在文档的每个方法进行说明
// Use the Kind method to find out the kind of value before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run time panic.
如果要调用这个类型的特定方法之前,请先判断这个类型,否则将panic
//
// The zero Value represents no value.
// Its IsValid method returns false, its Kind method returns Invalid,
// its String method returns "<invalid Value>", and all other methods panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
IsValid 这个方法没有值的时候返回flase
String 这个方法返回的是 <invalid Value>
其它的方法返回 invalid value ,如果有这样的情况,请在文档中说明
//
// A Value can be used concurrently by multiple goroutines provided that
// the underlying Go value can be used concurrently for the equivalent
// direct operations.
一个 Value 可以被多个 goroutine 同时使用,前提是底层的 Go 值可以同时用于等效的直接操作。
//
// To compare two Values, compare the results of the Interface method.
// Using == on two Values does not compare the underlying values
// they represent.
type Value struct {
// typ holds the type of the value represented by a Value.
typ *rtype
// Pointer-valued data or, if flagIndir is set, pointer to data.
// Valid when either flagIndir is set or typ.pointers() is true.
ptr unsafe.Pointer
// flag holds metadata about the value.
表示 值的元数据了类型
// The lowest bits are flag bits:
// - flagStickyRO: obtained via unexported not embedded field, so read-only 私有变量
// - flagEmbedRO: obtained via unexported embedded field, so read-only 嵌入的结构体
// - flagIndir: val holds a pointer to the data 指针类型
// - flagAddr: v.CanAddr is true (implies flagIndir)
// - flagMethod: v is a method value.
// The next five bits give the Kind of the value.
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
// If ifaceIndir(typ), code can assume that flagIndir is set.
flag
// A method value represents a curried method invocation
// like r.Read for some receiver r. The typ+val+flag bits describe
// the receiver r, but the flag's Kind bits say Func (methods are
// functions), and the top bits of the flag give the method number
// in r's type's method table.
}
type flag uintptr
// Tests for deep equality using reflected types. The map argument tracks
// comparisons that have already been seen, which allows short circuiting on
// recursive types.
func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
if !v1.IsValid() || !v2.IsValid() { // 判断是否是0值, 或panic
return v1.IsValid() == v2.IsValid()
}
if v1.Type() != v2.Type() { // 判断两值 类型是否一致
return false
}
// We want to avoid putting more in the visited map than we need to.
// For any possible reference cycle that might be encountered,
// hard(v1, v2) needs to return true for at least one of the types in the cycle,
// and it's safe and valid to get Value's internal pointer.
hard := func(v1, v2 Value) bool {
switch v1.Kind() {
case Ptr:
if v1.typ.ptrdata == 0 {
// go:notinheap pointers can't be cyclic.
// At least, all of our current uses of go:notinheap have
// that property. The runtime ones aren't cyclic (and we don't use
// DeepEqual on them anyway), and the cgo-generated ones are
// all empty structs.
return false
}
fallthrough
case Map, Slice, Interface:
// Nil pointers cannot be cyclic. Avoid putting them in the visited map.
return !v1.IsNil() && !v2.IsNil()
}
return false
}
if hard(v1, v2) {
// For a Ptr or Map value, we need to check flagIndir,
// which we do by calling the pointer method.
// For Slice or Interface, flagIndir is always set,
// and using v.ptr suffices.
ptrval := func(v Value) unsafe.Pointer {
switch v.Kind() {
case Ptr, Map:
return v.pointer()
default:
return v.ptr
}
}
addr1 := ptrval(v1)
addr2 := ptrval(v2)
if uintptr(addr1) > uintptr(addr2) {
// Canonicalize order to reduce number of entries in visited.
// Assumes non-moving garbage collector.
addr1, addr2 = addr2, addr1
}
// Short circuit if references are already seen.
typ := v1.Type()
v := visit{addr1, addr2, typ}
if visited[v] {
return true
}
// Remember for later.
visited[v] = true
}
switch v1.Kind() {// 分类比较
case Array:
for i := 0; i < v1.Len(); i++ {
if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
return false
}
}
return true
case Slice: // 切片
if v1.IsNil() != v2.IsNil() {
return false
}
if v1.Len() != v2.Len() { // 比较长度
return false
}
if v1.Pointer() == v2.Pointer() { // 比较首地址
return true
}
for i := 0; i < v1.Len(); i++ { // 比较里面的元素
if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
return false
}
}
return true
case Interface:
if v1.IsNil() || v2.IsNil() {
return v1.IsNil() == v2.IsNil()
}
return deepValueEqual(v1.Elem(), v2.Elem(), visited) // 比较接口里面的每一个字段
case Ptr:
if v1.Pointer() == v2.Pointer() {
return true
}
return deepValueEqual(v1.Elem(), v2.Elem(), visited)
case Struct:
for i, n := 0, v1.NumField(); i < n; i++ {
if !deepValueEqual(v1.Field(i), v2.Field(i), visited) {
return false
}
}
return true
case Map:
if v1.IsNil() != v2.IsNil() {
return false
}
if v1.Len() != v2.Len() {
return false
}
if v1.Pointer() == v2.Pointer() {
return true
}
for _, k := range v1.MapKeys() {
val1 := v1.MapIndex(k)
val2 := v2.MapIndex(k)
if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited) {
return false
}
}
return true
case Func:
if v1.IsNil() && v2.IsNil() {
return true
}
// Can't do better than this:
return false
default:
// Normal equality suffices
return valueInterface(v1, false) == valueInterface(v2, false)
}
}