github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/internal/reflect/slice.go (about) 1 package reflect 2 3 import ( 4 "fmt" 5 "reflect" 6 "unsafe" 7 ) 8 9 // SliceHeader unsafe.Pointer使得编译器能够正确识别指针 10 type SliceHeader struct { 11 Data unsafe.Pointer 12 Len int 13 Cap int 14 } 15 16 func SliceBackSpace(p interface{}, n uint) interface{} { 17 val := reflect.ValueOf(p) 18 if val.Kind() != reflect.Slice { 19 panic("type is not a slice") 20 } 21 sizeOf := val.Index(0).Type().Size() 22 eface := (*Eface)(unsafe.Pointer(&p)) 23 header := (*SliceHeader)(eface.data) 24 header.Data = unsafe.Pointer((uintptr)(header.Data) - uintptr(n)*sizeOf) 25 header.Len += int(n) 26 header.Cap += int(n) 27 return *(*interface{})(unsafe.Pointer(eface)) 28 } 29 30 // SliceIndex 支持负数索引 31 func SliceIndex(p interface{}, n int) interface{} { 32 val := reflect.ValueOf(p) 33 if val.Kind() != reflect.Slice { 34 panic("type is not a slice") 35 } 36 // index out range? 37 length := val.Len() 38 if length-1 < n || length < -n { 39 panic(fmt.Sprintf("index out range [%d:%d]", n, length)) 40 } 41 if -n > 0 { 42 return val.Index(length - (-n)).Interface() 43 } else { 44 return val.Index(n).Interface() 45 } 46 }