golang 切片、DeepEqual

切片:动态数组,底层也是数组

切片的结构

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== nilreflect.DeepEqual( x , nil)
a声明一个切片0x0truetrue
b声明并赋值0xc000056de0falsefalse
c声明并赋值 简化操作0xc000056de0falsefalse

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)
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值