mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 19:54:21 +08:00
good good study, day day up!
This commit is contained in:
28
vendor/gopl.io/ch13/bzip-print/bzip2.c
generated
vendored
Normal file
28
vendor/gopl.io/ch13/bzip-print/bzip2.c
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
// This is the version that appears in print,
|
||||
// but it does not comply with the proposed
|
||||
// rules for passing pointers between Go and C.
|
||||
// (https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md)
|
||||
// See gopl.io/ch13/bzip for an updated version.
|
||||
|
||||
//!+
|
||||
/* This file is gopl.io/ch13/bzip/bzip2.c, */
|
||||
/* a simple wrapper for libbzip2 suitable for cgo. */
|
||||
#include <bzlib.h>
|
||||
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen) {
|
||||
s->next_in = in;
|
||||
s->avail_in = *inlen;
|
||||
s->next_out = out;
|
||||
s->avail_out = *outlen;
|
||||
int r = BZ2_bzCompress(s, action);
|
||||
*inlen -= s->avail_in;
|
||||
*outlen -= s->avail_out;
|
||||
return r;
|
||||
}
|
||||
|
||||
//!-
|
||||
96
vendor/gopl.io/ch13/bzip-print/bzip2.go
generated
vendored
Normal file
96
vendor/gopl.io/ch13/bzip-print/bzip2.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
// This is the version that appears in print,
|
||||
// but it does not comply with the proposed
|
||||
// rules for passing pointers between Go and C.
|
||||
// (https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md)
|
||||
// See gopl.io/ch13/bzip for an updated version.
|
||||
//!+
|
||||
|
||||
// Package bzip provides a writer that uses bzip2 compression (bzip.org).
|
||||
package bzip
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I/usr/include
|
||||
#cgo LDFLAGS: -L/usr/lib -lbz2
|
||||
#include <bzlib.h>
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
w io.Writer // underlying output stream
|
||||
stream *C.bz_stream
|
||||
outbuf [64 * 1024]byte
|
||||
}
|
||||
|
||||
// NewWriter returns a writer for bzip2-compressed streams.
|
||||
func NewWriter(out io.Writer) io.WriteCloser {
|
||||
const (
|
||||
blockSize = 9
|
||||
verbosity = 0
|
||||
workFactor = 30
|
||||
)
|
||||
w := &writer{w: out, stream: new(C.bz_stream)}
|
||||
C.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)
|
||||
return w
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
//!+write
|
||||
func (w *writer) Write(data []byte) (int, error) {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
var total int // uncompressed bytes written
|
||||
|
||||
for len(data) > 0 {
|
||||
inlen, outlen := C.uint(len(data)), C.uint(cap(w.outbuf))
|
||||
C.bz2compress(w.stream, C.BZ_RUN,
|
||||
(*C.char)(unsafe.Pointer(&data[0])), &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
total += int(inlen)
|
||||
data = data[inlen:]
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return total, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
//!-write
|
||||
|
||||
//!+close
|
||||
// Close flushes the compressed data and closes the stream.
|
||||
// It does not close the underlying io.Writer.
|
||||
func (w *writer) Close() error {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
defer func() {
|
||||
C.BZ2_bzCompressEnd(w.stream)
|
||||
w.stream = nil
|
||||
}()
|
||||
for {
|
||||
inlen, outlen := C.uint(0), C.uint(cap(w.outbuf))
|
||||
r := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return err
|
||||
}
|
||||
if r == C.BZ_STREAM_END {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-close
|
||||
40
vendor/gopl.io/ch13/bzip-print/bzip2_test.go
generated
vendored
Normal file
40
vendor/gopl.io/ch13/bzip-print/bzip2_test.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package bzip_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/bzip2" // reader
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"gopl.io/ch13/bzip" // writer
|
||||
)
|
||||
|
||||
func TestBzip2(t *testing.T) {
|
||||
var compressed, uncompressed bytes.Buffer
|
||||
w := bzip.NewWriter(&compressed)
|
||||
|
||||
// Write a repetitive message in a million pieces,
|
||||
// compressing one copy but not the other.
|
||||
tee := io.MultiWriter(w, &uncompressed)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
io.WriteString(tee, "hello")
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check the size of the compressed stream.
|
||||
if got, want := compressed.Len(), 255; got != want {
|
||||
t.Errorf("1 million hellos compressed to %d bytes, want %d", got, want)
|
||||
}
|
||||
|
||||
// Decompress and compare with original.
|
||||
var decompressed bytes.Buffer
|
||||
io.Copy(&decompressed, bzip2.NewReader(&compressed))
|
||||
if !bytes.Equal(uncompressed.Bytes(), decompressed.Bytes()) {
|
||||
t.Error("decompression yielded a different message")
|
||||
}
|
||||
}
|
||||
32
vendor/gopl.io/ch13/bzip/bzip2.c
generated
vendored
Normal file
32
vendor/gopl.io/ch13/bzip/bzip2.c
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
//
|
||||
// The version of this program that appeared in the first and second
|
||||
// printings did not comply with the proposed rules for passing
|
||||
// pointers between Go and C, described here:
|
||||
// https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md
|
||||
//
|
||||
// The version below, which appears in the third printing,
|
||||
// has been corrected. See bzip2.go for explanation.
|
||||
|
||||
//!+
|
||||
/* This file is gopl.io/ch13/bzip/bzip2.c, */
|
||||
/* a simple wrapper for libbzip2 suitable for cgo. */
|
||||
#include <bzlib.h>
|
||||
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen) {
|
||||
s->next_in = in;
|
||||
s->avail_in = *inlen;
|
||||
s->next_out = out;
|
||||
s->avail_out = *outlen;
|
||||
int r = BZ2_bzCompress(s, action);
|
||||
*inlen -= s->avail_in;
|
||||
*outlen -= s->avail_out;
|
||||
s->next_in = s->next_out = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
//!-
|
||||
111
vendor/gopl.io/ch13/bzip/bzip2.go
generated
vendored
Normal file
111
vendor/gopl.io/ch13/bzip/bzip2.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
//
|
||||
// The version of this program that appeared in the first and second
|
||||
// printings did not comply with the proposed rules for passing
|
||||
// pointers between Go and C, described here:
|
||||
// https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md
|
||||
//
|
||||
// The rules forbid a C function like bz2compress from storing 'in'
|
||||
// and 'out' (pointers to variables allocated by Go) into the Go
|
||||
// variable 's', even temporarily.
|
||||
//
|
||||
// The version below, which appears in the third printing, has been
|
||||
// corrected. To comply with the rules, the bz_stream variable must
|
||||
// be allocated by C code. We have introduced two C functions,
|
||||
// bz2alloc and bz2free, to allocate and free instances of the
|
||||
// bz_stream type. Also, we have changed bz2compress so that before
|
||||
// it returns, it clears the fields of the bz_stream that contain
|
||||
// pointers to Go variables.
|
||||
|
||||
//!+
|
||||
|
||||
// Package bzip provides a writer that uses bzip2 compression (bzip.org).
|
||||
package bzip
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I/usr/include
|
||||
#cgo LDFLAGS: -L/usr/lib -lbz2
|
||||
#include <bzlib.h>
|
||||
#include <stdlib.h>
|
||||
bz_stream* bz2alloc() { return calloc(1, sizeof(bz_stream)); }
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen);
|
||||
void bz2free(bz_stream* s) { free(s); }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
w io.Writer // underlying output stream
|
||||
stream *C.bz_stream
|
||||
outbuf [64 * 1024]byte
|
||||
}
|
||||
|
||||
// NewWriter returns a writer for bzip2-compressed streams.
|
||||
func NewWriter(out io.Writer) io.WriteCloser {
|
||||
const blockSize = 9
|
||||
const verbosity = 0
|
||||
const workFactor = 30
|
||||
w := &writer{w: out, stream: C.bz2alloc()}
|
||||
C.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)
|
||||
return w
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
//!+write
|
||||
func (w *writer) Write(data []byte) (int, error) {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
var total int // uncompressed bytes written
|
||||
|
||||
for len(data) > 0 {
|
||||
inlen, outlen := C.uint(len(data)), C.uint(cap(w.outbuf))
|
||||
C.bz2compress(w.stream, C.BZ_RUN,
|
||||
(*C.char)(unsafe.Pointer(&data[0])), &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
total += int(inlen)
|
||||
data = data[inlen:]
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return total, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
//!-write
|
||||
|
||||
//!+close
|
||||
// Close flushes the compressed data and closes the stream.
|
||||
// It does not close the underlying io.Writer.
|
||||
func (w *writer) Close() error {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
defer func() {
|
||||
C.BZ2_bzCompressEnd(w.stream)
|
||||
C.bz2free(w.stream)
|
||||
w.stream = nil
|
||||
}()
|
||||
for {
|
||||
inlen, outlen := C.uint(0), C.uint(cap(w.outbuf))
|
||||
r := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return err
|
||||
}
|
||||
if r == C.BZ_STREAM_END {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-close
|
||||
40
vendor/gopl.io/ch13/bzip/bzip2_test.go
generated
vendored
Normal file
40
vendor/gopl.io/ch13/bzip/bzip2_test.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package bzip_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/bzip2" // reader
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"gopl.io/ch13/bzip" // writer
|
||||
)
|
||||
|
||||
func TestBzip2(t *testing.T) {
|
||||
var compressed, uncompressed bytes.Buffer
|
||||
w := bzip.NewWriter(&compressed)
|
||||
|
||||
// Write a repetitive message in a million pieces,
|
||||
// compressing one copy but not the other.
|
||||
tee := io.MultiWriter(w, &uncompressed)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
io.WriteString(tee, "hello")
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check the size of the compressed stream.
|
||||
if got, want := compressed.Len(), 255; got != want {
|
||||
t.Errorf("1 million hellos compressed to %d bytes, want %d", got, want)
|
||||
}
|
||||
|
||||
// Decompress and compare with original.
|
||||
var decompressed bytes.Buffer
|
||||
io.Copy(&decompressed, bzip2.NewReader(&compressed))
|
||||
if !bytes.Equal(uncompressed.Bytes(), decompressed.Bytes()) {
|
||||
t.Error("decompression yielded a different message")
|
||||
}
|
||||
}
|
||||
29
vendor/gopl.io/ch13/bzipper/main.go
generated
vendored
Normal file
29
vendor/gopl.io/ch13/bzipper/main.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 365.
|
||||
|
||||
//!+
|
||||
|
||||
// Bzipper reads input, bzip2-compresses it, and writes it out.
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gopl.io/ch13/bzip"
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := bzip.NewWriter(os.Stdout)
|
||||
if _, err := io.Copy(w, os.Stdin); err != nil {
|
||||
log.Fatalf("bzipper: %v\n", err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
log.Fatalf("bzipper: close: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
||||
127
vendor/gopl.io/ch13/equal/equal.go
generated
vendored
Normal file
127
vendor/gopl.io/ch13/equal/equal.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 359.
|
||||
|
||||
// Package equal provides a deep equivalence relation for arbitrary values.
|
||||
package equal
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//!+
|
||||
func equal(x, y reflect.Value, seen map[comparison]bool) bool {
|
||||
if !x.IsValid() || !y.IsValid() {
|
||||
return x.IsValid() == y.IsValid()
|
||||
}
|
||||
if x.Type() != y.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
// ...cycle check omitted (shown later)...
|
||||
|
||||
//!-
|
||||
//!+cyclecheck
|
||||
// cycle check
|
||||
if x.CanAddr() && y.CanAddr() {
|
||||
xptr := unsafe.Pointer(x.UnsafeAddr())
|
||||
yptr := unsafe.Pointer(y.UnsafeAddr())
|
||||
if xptr == yptr {
|
||||
return true // identical references
|
||||
}
|
||||
c := comparison{xptr, yptr, x.Type()}
|
||||
if seen[c] {
|
||||
return true // already seen
|
||||
}
|
||||
seen[c] = true
|
||||
}
|
||||
//!-cyclecheck
|
||||
//!+
|
||||
switch x.Kind() {
|
||||
case reflect.Bool:
|
||||
return x.Bool() == y.Bool()
|
||||
|
||||
case reflect.String:
|
||||
return x.String() == y.String()
|
||||
|
||||
// ...numeric cases omitted for brevity...
|
||||
|
||||
//!-
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64:
|
||||
return x.Int() == y.Int()
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64, reflect.Uintptr:
|
||||
return x.Uint() == y.Uint()
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return x.Float() == y.Float()
|
||||
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return x.Complex() == y.Complex()
|
||||
//!+
|
||||
case reflect.Chan, reflect.UnsafePointer, reflect.Func:
|
||||
return x.Pointer() == y.Pointer()
|
||||
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return equal(x.Elem(), y.Elem(), seen)
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < x.Len(); i++ {
|
||||
if !equal(x.Index(i), y.Index(i), seen) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
// ...struct and map cases omitted for brevity...
|
||||
//!-
|
||||
case reflect.Struct:
|
||||
for i, n := 0, x.NumField(); i < n; i++ {
|
||||
if !equal(x.Field(i), y.Field(i), seen) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case reflect.Map:
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
for _, k := range x.MapKeys() {
|
||||
if !equal(x.MapIndex(k), y.MapIndex(k), seen) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
//!+
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
//!+comparison
|
||||
// Equal reports whether x and y are deeply equal.
|
||||
//!-comparison
|
||||
//
|
||||
// Map keys are always compared with ==, not deeply.
|
||||
// (This matters for keys containing pointers or interfaces.)
|
||||
//!+comparison
|
||||
func Equal(x, y interface{}) bool {
|
||||
seen := make(map[comparison]bool)
|
||||
return equal(reflect.ValueOf(x), reflect.ValueOf(y), seen)
|
||||
}
|
||||
|
||||
type comparison struct {
|
||||
x, y unsafe.Pointer
|
||||
t reflect.Type
|
||||
}
|
||||
|
||||
//!-comparison
|
||||
133
vendor/gopl.io/ch13/equal/equal_test.go
generated
vendored
Normal file
133
vendor/gopl.io/ch13/equal/equal_test.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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
|
||||
}
|
||||
38
vendor/gopl.io/ch13/unsafeptr/main.go
generated
vendored
Normal file
38
vendor/gopl.io/ch13/unsafeptr/main.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 357.
|
||||
|
||||
// Package unsafeptr demonstrates basic use of unsafe.Pointer.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//!+main
|
||||
var x struct {
|
||||
a bool
|
||||
b int16
|
||||
c []int
|
||||
}
|
||||
|
||||
// equivalent to pb := &x.b
|
||||
pb := (*int16)(unsafe.Pointer(
|
||||
uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)))
|
||||
*pb = 42
|
||||
|
||||
fmt.Println(x.b) // "42"
|
||||
//!-main
|
||||
}
|
||||
|
||||
/*
|
||||
//!+wrong
|
||||
// NOTE: subtly incorrect!
|
||||
tmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
|
||||
pb := (*int16)(unsafe.Pointer(tmp))
|
||||
*pb = 42
|
||||
//!-wrong
|
||||
*/
|
||||
Reference in New Issue
Block a user