It suddenly occurred to me that it was very like `re-slice` —— as long as part of the underlying array is referenced, the whole underlying array is never gc-ed. I guess there is a method in gc which could locate the whole underlying array as long as one address inside the array's address interval was provided? So now I tend to believe that `Element1` is correct too, and the `underlyBuf` filed in `Element2` is redundant and is not quite necessary, am I correct?
On Sunday, February 6, 2022 at 10:08:06 AM UTC+8 rmfr wrote: > Please take a look at the following code: > > ```go > package main > > import ( > "fmt" > "runtime" > "unsafe" > ) > > func assert(b bool) { > if b { > } else { > panic("unexpected") > } > } > > type Elementer interface { > GetInt64Slice() []int64 > GetByteSlice() []byte > String() string > } > > type Element1 struct { > int64s []int64 > bs []byte > } > > func newElement1(int64Sz, bsSz int) *Element1 { > assert(int64Sz > 0 && bsSz > 0) > len0 := int64Sz * 8 > len1 := bsSz > buf := make([]byte, len0+len1) > for i := range buf { > buf[i] = byte(i) > } > e := &Element1{ > int64s: unsafe.Slice((*int64)(unsafe.Pointer(&buf[0])), int64Sz), > bs: unsafe.Slice((*byte)(&buf[len0]), bsSz), > } > return e > } > > func (e *Element1) GetInt64Slice() []int64 { > return e.int64s > } > > func (e *Element1) GetByteSlice() []byte { > return e.bs > } > > func (e *Element1) String() string { > return fmt.Sprintf("Element1:[% x % x]", e.GetInt64Slice(), > e.GetByteSlice()) > } > > type Element2 struct { > underlyBuf []byte // <- is this field needed? > int64s []int64 > bs []byte > } > > func newElement2(int64Sz, bsSz int) *Element2 { > assert(int64Sz > 0 && bsSz > 0) > len0 := int64Sz * 8 > len1 := bsSz > buf := make([]byte, len0+len1) > for i := range buf { > buf[i] = byte(i) > } > e := &Element2{ > underlyBuf: buf, // <- > int64s: unsafe.Slice((*int64)(unsafe.Pointer(&buf[0])), > int64Sz), > bs: unsafe.Slice((*byte)(&buf[len0]), bsSz), > } > return e > } > > func (e *Element2) GetInt64Slice() []int64 { > runtime.KeepAlive(e.underlyBuf) > return e.int64s > } > > func (e *Element2) GetByteSlice() []byte { > runtime.KeepAlive(e.underlyBuf) > return e.bs > } > > func (e *Element2) String() string { > runtime.KeepAlive(e.underlyBuf) > return fmt.Sprintf("Element2:[% x % x]", e.GetInt64Slice(), > e.GetByteSlice()) > } > > func main() { > var e Elementer > fmt.Println("print with host endian:") > e = newElement1(2, 4) > fmt.Println("hi", e) > e = newElement2(2, 4) > fmt.Println("hi", e) > } > ``` > > And which yields: > > ``` > hi Element1:[[ 706050403020100 f0e0d0c0b0a0908] 10 11 12 13] > hi Element2:[[ 706050403020100 f0e0d0c0b0a0908] 10 11 12 13] > ``` > > I'm not sure whether the `underlyBuf` filed in `Element2` is needed or > not. When I'm reading the doc from ` > https://pkg.go.dev/reflect#SliceHeader` > <https://pkg.go.dev/reflect#SliceHeader> there is: > > > Moreover, the Data field is not sufficient to guarantee the data it > references will not be garbage collected, so programs must keep a separate, > correctly typed pointer to the underlying data. > > But in `https://pkg.go.dev/unsafe#Slice` <https://pkg.go.dev/unsafe#Slice> > there are no such comments. So the question: > > Which implementation of `Elementer` is correct? `Element2` or both of them? > > Thanks a lot for your help. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/3af951b7-2e5c-40d2-8b61-ddc59c97eef3n%40googlegroups.com.