mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-05 14:03:45 +00:00
134 lines
3.0 KiB
Go
134 lines
3.0 KiB
Go
|
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||
|
|
||
|
package equal
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestEqual(t *testing.T) {
|
||
|
one, oneAgain, two := 1, 1, 2
|
||
|
|
||
|
type CyclePtr *CyclePtr
|
||
|
var cyclePtr1, cyclePtr2 CyclePtr
|
||
|
cyclePtr1 = &cyclePtr1
|
||
|
cyclePtr2 = &cyclePtr2
|
||
|
|
||
|
type CycleSlice []CycleSlice
|
||
|
var cycleSlice CycleSlice
|
||
|
cycleSlice = append(cycleSlice, cycleSlice)
|
||
|
|
||
|
ch1, ch2 := make(chan int), make(chan int)
|
||
|
var ch1ro <-chan int = ch1
|
||
|
|
||
|
type mystring string
|
||
|
|
||
|
var iface1, iface1Again, iface2 interface{} = &one, &oneAgain, &two
|
||
|
|
||
|
for _, test := range []struct {
|
||
|
x, y interface{}
|
||
|
want bool
|
||
|
}{
|
||
|
// basic types
|
||
|
{1, 1, true},
|
||
|
{1, 2, false}, // different values
|
||
|
{1, 1.0, false}, // different types
|
||
|
{"foo", "foo", true},
|
||
|
{"foo", "bar", false},
|
||
|
{mystring("foo"), "foo", false}, // different types
|
||
|
// slices
|
||
|
{[]string{"foo"}, []string{"foo"}, true},
|
||
|
{[]string{"foo"}, []string{"bar"}, false},
|
||
|
{[]string{}, []string(nil), true},
|
||
|
// slice cycles
|
||
|
{cycleSlice, cycleSlice, true},
|
||
|
// maps
|
||
|
{
|
||
|
map[string][]int{"foo": {1, 2, 3}},
|
||
|
map[string][]int{"foo": {1, 2, 3}},
|
||
|
true,
|
||
|
},
|
||
|
{
|
||
|
map[string][]int{"foo": {1, 2, 3}},
|
||
|
map[string][]int{"foo": {1, 2, 3, 4}},
|
||
|
false,
|
||
|
},
|
||
|
{
|
||
|
map[string][]int{},
|
||
|
map[string][]int(nil),
|
||
|
true,
|
||
|
},
|
||
|
// pointers
|
||
|
{&one, &one, true},
|
||
|
{&one, &two, false},
|
||
|
{&one, &oneAgain, true},
|
||
|
{new(bytes.Buffer), new(bytes.Buffer), true},
|
||
|
// pointer cycles
|
||
|
{cyclePtr1, cyclePtr1, true},
|
||
|
{cyclePtr2, cyclePtr2, true},
|
||
|
{cyclePtr1, cyclePtr2, true}, // they're deeply equal
|
||
|
// functions
|
||
|
{(func())(nil), (func())(nil), true},
|
||
|
{(func())(nil), func() {}, false},
|
||
|
{func() {}, func() {}, false},
|
||
|
// arrays
|
||
|
{[...]int{1, 2, 3}, [...]int{1, 2, 3}, true},
|
||
|
{[...]int{1, 2, 3}, [...]int{1, 2, 4}, false},
|
||
|
// channels
|
||
|
{ch1, ch1, true},
|
||
|
{ch1, ch2, false},
|
||
|
{ch1ro, ch1, false}, // NOTE: not equal
|
||
|
// interfaces
|
||
|
{&iface1, &iface1, true},
|
||
|
{&iface1, &iface2, false},
|
||
|
{&iface1Again, &iface1, true},
|
||
|
} {
|
||
|
if Equal(test.x, test.y) != test.want {
|
||
|
t.Errorf("Equal(%v, %v) = %t",
|
||
|
test.x, test.y, !test.want)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func Example_equal() {
|
||
|
//!+
|
||
|
fmt.Println(Equal([]int{1, 2, 3}, []int{1, 2, 3})) // "true"
|
||
|
fmt.Println(Equal([]string{"foo"}, []string{"bar"})) // "false"
|
||
|
fmt.Println(Equal([]string(nil), []string{})) // "true"
|
||
|
fmt.Println(Equal(map[string]int(nil), map[string]int{})) // "true"
|
||
|
//!-
|
||
|
|
||
|
// Output:
|
||
|
// true
|
||
|
// false
|
||
|
// true
|
||
|
// true
|
||
|
}
|
||
|
|
||
|
func Example_equalCycle() {
|
||
|
//!+cycle
|
||
|
// Circular linked lists a -> b -> a and c -> c.
|
||
|
type link struct {
|
||
|
value string
|
||
|
tail *link
|
||
|
}
|
||
|
a, b, c := &link{value: "a"}, &link{value: "b"}, &link{value: "c"}
|
||
|
a.tail, b.tail, c.tail = b, a, c
|
||
|
fmt.Println(Equal(a, a)) // "true"
|
||
|
fmt.Println(Equal(b, b)) // "true"
|
||
|
fmt.Println(Equal(c, c)) // "true"
|
||
|
fmt.Println(Equal(a, b)) // "false"
|
||
|
fmt.Println(Equal(a, c)) // "false"
|
||
|
//!-cycle
|
||
|
|
||
|
// Output:
|
||
|
// true
|
||
|
// true
|
||
|
// true
|
||
|
// false
|
||
|
// false
|
||
|
}
|