Slicing a pointer to slice - go

When I'm following this golang blog post about arrays and slices, I tried to pass a pointer to a slice to a function that modify the underlying len property in the slice header:
func PtrSubtractOneFromLength(slicePtr *[]byte) {
slice := *slicePtr
*slicePtr = slice[0 : len(slice)-1]
}
And when I tried to refactor it to this from:
func PtrSubtractOneFromLength(slicePtr *[]int) {
*slicePtr = *slicePtr[0 : len(*slicePtr)-1]
}
I get this error
cannot slice slicePtr (type *[]int)
Where is the magic in the slice := *slicePtr statement?

A slice expression binds stronger than a dereference. Try this:
*slicePtr = (*slicePtr)[0 : len(*slicePtr)-1]

Related

How to get the element type of slice?

If there is a struct like:
type A struct {
Arr []int
}
How can I get the element type in the slice arr?
for example, an empty A instance is passed in, how can I get the int type?
func PrintElementType(obj interface{}) {
objType := reflect.TypeOf(obj)
for i := 0; i < objType.NumField(); i++ {
fieldType := objType.Field(i).Type
// here I got 'slice'
fmt.Println(fieldType.Kind())
// here I got '[]int', I think 'int' type is stored somewhere...
fmt.Println(fieldType)
// so, is there any way to get 'int' type?
fmt.Println("inner element type?")
}
}
func main() {
a := A{}
PrintElementType(a)
}
If you have the reflect.Type type descriptor of a slice type, use its Type.Elem() method to get the type descriptor of the slice's element type:
fmt.Println(fieldType.Elem())
Type.Elem() may also be used to get the element type if the type's Kind is Array, Chan, Map, Ptr, or Slice, but it panics otherwise. So you should check the kind before calling it:
if fieldType.Kind() == reflect.Slice {
fmt.Println("Slice's element type:", fieldType.Elem())
}
This will output (try it on the Go Playground):
slice
[]int
Slice's element type: int

cast interface{} to []interface{}

How can I cast an interface{} to []interface{} ?
rt := reflect.ValueOf(raw)
switch rt.Kind() {
case reflect.Slice:
src := raw.([]interface{}) //this operation errors out
for _,_ := range src {
//some operation
}
}
I get an error panic: interface conversion: interface {} is []string, not []interface {}
I want make this method generic enough to handle any type, not a fixed type.
I'm very new to Go and I'm stuck with this problem, most likely I'm doing it wrong. Any suggestion how can I get around this ?
Edit:
Some operation is json.Marshal which return byte array.
What I'm really trying to do:
I have a function that receives interface type, if it is an array/slice then I would like to run json.Marshal on each item rather than apply it as a whole. Basically, I'm trying to break up the JSON blob if the first level object is an array, and yes it needs to be generic.
As the error message states, a []string is not an []interface{}. See the FAQ for an explanation.
Use the reflect API do to this generically:
v := reflect.ValueOf(raw)
switch v.Kind() {
case reflect.Slice:
for i := 0; i < v.Len(); i++ {
elem := v.Index(i).Interface()
// elem is an element of the slice
}
}
Run it on the Playground.

interface{} variable to []interface{}

I have an interface{} variable and I know it's a pointer to slice:
func isPointerToSlice(val interface{}) bool {
value := reflect.ValueOf(val)
return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}
But I'm finding difficult to type cast it into an []interface{} variable:
if isPointerToSlice(val) {
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
// 'worked' is false :(
}
This doesn't work. Any idea how can I solve this?
If you just want to convert a slice to []interface{} you can use something like this:
func sliceToIfaceSlice(val interface{}) []interface{} {
rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer
if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
// panic("expected a slice or array")
return nil
}
out := make([]interface{}, rf.Len())
for i := range out {
out[i] = rf.Index(i).Interface()
}
return out
}
playground
You can simply use type assertion to obtain the value stored in an interface, e.g.
if isPointerToSlice(val) {
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
} else {
fmt.Println("Not *[]interface{}")
}
The type of the value stored in the interface as you claim is pointer to []interface{}, which is *[]interface{}. The result of the type assertion will be a pointer, just dereference it to get the slice []interface{}.
Using short variable declaration:
result := *val.(*[]interface{}) // type of result is []interface{}
Try it on the Go Playground.
Also your attempt also works:
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)
Here's the edited the Playground example which proves your solution works.
But using reflection is unnecessary (as it can be done with type assertion).
Also note that *[]interface{} and *[]someOtherType are 2 different types and you can't obtain a value of *[]interface{} if there is something else in val.
Icza's answer is great and will work especially if you can't know for sure you are getting an interface slice, however if you don't want to bother with the reflect package at all and want to keep imported code low, you can use type switching to obtain the same functionality using only built-in methods.
Using this method, you can shorten your code to just:
package main
import (
"fmt"
)
func main() {
s := []interface{}{"one", 2}
p := &s
do(p)
}
func do(val interface{}) {
switch val.(type){
case *[]interface{}:
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
}
}
Playground: http://play.golang.org/p/DT_hb8JcVt
The downside is if you don't know the exact type of slice you are receiving beforehand, then this will not work unless you list all possible types for handling and assertion.

In golang, how to embed on custom type?

I have custom types Int64Array, Channel and ChannelList like:
type Int64Array []int64
func (ia *Int64Array) Scan(src interface{}) error {
rawArray := string(src.([]byte))
if rawArray == "{}" {
*ia = []int64{}
} else {
matches := pgArrayPat.FindStringSubmatch(rawArray)
if len(matches) > 1 {
for _, item := range strings.Split(matches[1], ",") {
i, _ := strconv.ParseInt(item, 10, 64)
*ia = append(*ia, i)
}
}
}
return nil
}
func (ia Int64Array) Value() (driver.Value, error) {
var items []string
for _, item := range ia {
items = append(items, strconv.FormatInt(int64(item), 10))
}
return fmt.Sprintf("{%s}", strings.Join(items, ",")), nil
}
type Channel int64
type ChannelList []Channel
How can I embed Int64Array to ChannelList such that I can call Scan and Value methods on it? I tried the following:
type ChannelList []Channel {
Int64Array
}
but I'm getting syntax error. What's important is to make sure ChannelList items are of type Channel, if this isn't possible via embedding I might just create stand-alone functions to be called by both ChannelList and Int64Array.
An anonymous (or embedded field) is found in a struct (see struct type), not in a type alias (or "type declaration").
You cannot embed a type declaration within another type declaration.
Plus, as illustrated by the answers to "Go: using a pointer to array", you shouldn't be using pointers to slice, use directly the slice themselves (passed by value).
Wessie kindly points out in the comments that (ia *Int64Array) Scan() uses pointer to a slice in order to mutate the underlying array referenced by said slice.
I would prefer returning another slice instead of mutating the existing one.
That being said, the Golang Code Review does mention:
If the receiver is a struct, array or slice and any of its elements is a pointer to something that might be mutating, prefer a pointer receiver, as it will make the intention more clear to the reader.

Create a slice of type from a pointer to a type

Trying to create a slice in which the type is set dynamicaly based on a pointer to a specific type, so i made the following sample
func main() {
var chicken *Chicken
//create a slice of chickens
chickens:=GetaDynamiclyTypedSlice(chicken)
//this throws cannot range over chickens (type *[]interface {}) and i cant figure how to create a slice using my above chicken pointer
for _,chicken := range chickens{
fmt.Println(chicken)
}
}
type Chicken struct{
Weight float64
}
func GetaDynamiclyTypedSlice(ptrItemType interface{})*[]interface {}{
var collection []interface{}
itemtyp := reflect.TypeOf(ptrItemType).Elem()
for i:=0;i<1000;i++{
//create an item of the wanted type
item := reflect.New(itemtyp)
//set a random float to the weight value
item.Elem().FieldByName("Weight").SetFloat(rnd.ExpFloat64())
collection = append(collection,&item)
}
return &collection
}
what should i do to be able to use range on the returned slice?
how can i use the itemtyp as the type of my slice?
There are few problems with your code.
You're returning a pointer to a reflect.Value, 99% sure that's not what you're trying to achive.
You're not dereferencing the slice like Simon mentioned.
Slices are pointer types, if you're returning *[]interface{} for performance reasons, you're actually hurting not helping.
So let's rewrite the code and optimize it! (it's late night SO, time to party):
// pass the size to preallocate the slice, also return the correct slice type.
func GetaDynamiclyTypedSlice(ptrItemType interface{}, size int) (col []interface{}) {
col = make([]interface{}, size)
itemtyp := reflect.TypeOf(ptrItemType).Elem()
for i := range col { //prettier than for i := 0; etc etc
item := reflect.New(itemtyp)
item.Elem().FieldByName("Weight").SetFloat(rand.ExpFloat64())
col[i] = item.Interface() //this is the magic word, return the actual item, not reflect.Value
}
return
}
playground
You just need to dereference the pointer (so you're not iterating over a pointer - you're iterating over a slice):
for _, chicken := range *chickens {
// ...
}
Playground link: http://play.golang.org/p/NBv9sooqEV

Resources