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.

Reply via email to