Why can't range over *[]Struct? - arrays

http://play.golang.org/p/jdWZ9boyrh
I am getting this error
prog.go:29: invalid receiver type *[]Sentence ([]Sentence is an unnamed type)
prog.go:30: cannot range over S (type *[]Sentence)
[process exited with non-zero status]
when my function tries to receive structure array.
What does it mean by an unnamed type? Why can't it be named? I can name it outside function and also pass them as arguments with them being named.
It does not work. So I just passed []Sentence as an argument and solve the problem that I need to. But when passing them as arguments, I had to return a new copy.
I still think that it would be nice if I can just let the function receive the struct array and does not have to return anything.
Like below:
func (S *[]Sentence)MarkC() {
for _, elem := range S {
elem.mark = "C"
}
}
var arrayC []Sentence
for i:=0; i<5; i++ {
var new_st Sentence
new_st.index = i
arrayC = append(arrayC, new_st)
}
//MarkC(arrayC)
//fmt.Println(arrayC)
//Expecting [{0 C} {1 C} {2 C} {3 C} {4 C}]
//but not working
It is not working either with []Sentence.
Is there anyway that I can make a function receive Struct array?

I'm still learning Go but it seems that it wants the type named. You know, "array of sentences" - that is really an anonymous type. You just have to name it.
(also, use for or one-variable form of range to avoid copying elements (and discarding your changes))
type Sentence struct {
mark string
index int
}
type SentenceArr []Sentence
func (S SentenceArr)MarkC() {
for i := 0; i < len(S); i++ {
S[i].mark = "S"
}
}

Related

Iterating over a struct in Golang and print the value if set

First of all, apologies if this question is confused since I'm just trying out Go and have no idea what I'm doing. I have a struct composed of a variety of attributes of different types, example:
type foo struct {
bar string
baz int
bez []string
(...)
Initially I wanted to iterate over all these attributes and print the value if it existed, but I realized you cannot range over a struct the same way you could, say, a list or map. So I've tried out a few tricks with no luck (like trying to iterate over a separate list of attributes), and I think it's better I just ask for help because I'm probably in over my head here.
The idea is that if I create a new instance of this struct, I'd like to be able to then only print values that are set:
obj := foo{"bar_string", 1}
Given that the string slice bez is not set in obj, I'd like to be able to do something like (pseudo):
for i in obj:
print i
Giving:
"bar_string"
1
Ideally, not printing [] which I guess is the zero value for bez.
Am I approaching this whole thing wrong? The reason I'm not using a map is because I'd like the attributes to be different types, and I'd like future differing objects I'm working in to be organized into structs for clarity.
Go doesn't have builtin struct iteration. The for ... range statement is applicable only to:
all entries of an array, slice, string or map, or values received on a channel
or defined types with one of those underlying types (e.g. type Foo []int)
If you want to iterate over a struct known at compile time, you might be better off just accessing fields one by one.
If you want to must iterate over a struct not known at compile time, you can use the reflect package (not recommended):
type Foo struct {
Bar string
Baz int
Quux []int
}
// x := Foo{"bar", 1, nil}
func printAny(x interface{}) {
v := reflect.ValueOf(x)
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if !reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()) {
fmt.Println(field)
// bar
// 1
}
}
}
...but it's slower and there are some gotchas, for example:
field.Interface() panics if the field is unexported
in the if clause you can't just use the comparison operator == because operands might be not comparable:
you have to make sure that the zero value for field types is what you expect
If your goal is to just print the struct, you can simply implement the Stringer interface, where you can do type-safe checks the way you want without reflect:
type Foo struct {
Bar string
Baz int
Quux []int
}
func (f Foo) String() string {
s := []string{f.Bar, strconv.Itoa(f.Baz)}
if f.Quux != nil {
s = append(s, fmt.Sprintf("%v", f.Quux))
}
return strings.Join(s, "\n")
}
func main() {
fmt.Println(Foo{"bar", 1, nil})
// bar
// 1
}
A Go playground

How to access a slice in struct in golang

How can I access a slice defined inside the struct?
type Car struct {
Year int
Name string
Type []int
}
//Accessing "Type" array field as below causes error: array out of range.
Car.Type[0] = 12
Car.Type[1] = 15
Car.Type[2] = 11
You mistake slice for array. It must be:
type Car struct {
Year int
Name string
Type [3]int // <---
}
See running code
You should read this tour: https://tour.golang.org/moretypes/6
You can't directly access a slice field if it's not been initialised. You're defining a struct to have 3 fields: Year of type int, this is a simple value that is part of the struct. Same goes for Name. The Type field, however, is a slice. A slice is a reference type. That means it's essentially a hidden struct (called the slice header) with underlying pointer to an array that is allocated dynamically for you. This underlying pointer is, at the time you initialise your variable, nil.
type Car struct {
Year int
Name string
Type []int
}
Can be seen as:
type Car struct {
Year int
Name string
Type struct{
type: "int",
array *[]T
}
}
Not exactly, but you get the idea. When you write:
c := Car{}
All you've allocated is the int, string and the slice header. You must, therefore initialise the slice first:
c := Car{
Year: 2018,
Name: "vroom",
Type: []int{
1, 2, 3,
},
}
There are many ways to initialise the slice, of course. You don't have to set the values just yet, but you could, for example, allocate and initialise the memory you need in one go:
c.Type = make([]int, 3) // allocates an initialised 3 elements in the slice to 0
you can also allocate but not initialise the slice by specifying the capacity (this is useful to avoid reallocating and moving the slice around too often):
c.Type = make([]int, 0, 3)
Alternatively, you can have the runtime do it all for you, using append:
c.Type = append(c.Type, 1, 2, 3)
Some examples here
A bit more background. Slices and maps work similarly, broadly speaking. Because they are reference types, that rely on pointers internally, it's possible for functions that have a slice as a return type to return nil for example. This doesn't work for functions returning an int:
func nilSlice() []int {
return nil
}
Because the return type is a slice, what this function will return is, essentially, an empty slice. Accessing it will result in the same error you occurred: index out of range.
Trying to return nil from a function like this won't even compile:
func nilInt() int {
nil
}
The resulting error will say something like "Can't use nil as type int". Treat slices as pointer types: they need to be safely initialised before use. Always check their length, and if you need to optimise, look at how the builtin append function is implemented. It'll just exponentially grow the capacity of the underlying array. Something that you may not always want. It's trivial to optimise this sort of stuff
You are confusing Slices and Array. Slices are like dynamic arrays. The way you have defined the slice, their index is not defined until they are appended. For the above code:
type Car struct {
Type []int
}
var car Car
car.Type = append(car.Type, 12)
car.Type = append(car.Type, 15)
car.Type = append(car.Type, 11)
Also, Car in your case is a type of object not a object itself. I have declared object car of type Car.

Generic type array do not take empty array as input

import Foundation
func insertionSort<T where T: Comparable>(var items:[T])-> [T] {
for (index, _) in items.enumerate().dropFirst() {
var j = index
while ((j > 0) && (items[j] < items[j-1])) {
swap(&items[j], &items[j-1])
j = j-1
}
}
return items
}
// Test the function
insertionSort([]) // Generic type array is not taking empty array
When I am trying to call insertionSort with empty array, I get
Cannot invoke 'insertionSort' with an argument list of type '([_])'
I am not able to figure out how to fix this.
To call generic functions in Swift, Swift needs to be able to infer the generic parameters.
One way giving the type information to Swift, is using an intermediate variable.
(Like noted in Lu_'s comment.)
let arr: [Int] = []
let result = insertionSort(arr)
Another way is using as.
let result = insertionSort([] as [Int])
(Remember, var parameter does not modify the actual argument. It just makes a mutable copy, but does not write it back to the original argument. Swift 3 removed var parameters, as it's so confusing. You may need to assign the return value of the function to a variable.)

Getting Over Struct Implementation in Swift

In Swift, everything is implemented as a struct rather than a class. Values are being passed in, but the memory address does not store them. Here is an example:
import UIKit
var array = Array<Int>()
array = [6,2,9,1,10,4,9,3,5,8,7]
let count = array.count
func insertSort(var arr : Array<Int>)->(){
for(var i = 1; i<arr.count-1; i++){
var j : Int
for( j = i; j > 0; j--){
if(arr[j]<arr[j-1]){
var temp = arr[j-1]
var temp2 = arr[j]
arr.removeAtIndex(j-1)
arr.insert(temp2, atIndex: j-1)
arr.removeAtIndex(j)
arr.insert(temp, atIndex: j)
}
}
}
for item in arr{
print(item)
}
}
insertSort(array)
array
I know that this isn't the most concise way to implement an insertion sort, but I was just trying to use the most Swift I could.
My issue: through the print statement in the function, I can see that the algorithm works - the list is returned sorted. However, when I print the array at the bottom, Playground returns the same array as the one I declared at the top, ie unsorted. I know why that is (the array is not implemented as a class), I just wanted to know if there is a way to fix it.
To modify a value type passed to a function, you need to pass it as an inout parameter:
func insertSort(inout arr: [Int]) {
// etc.
}
insertSort(&array)
This is how Swift.sort is declared – try cmd-opt-clicking it in a playground or take a look at the Swifter docs.
inout should be used sparingly – one of the big benefits of structs is that they can be declared immutable with let, but immutable structs cannot be passed as inout parameters. This is why the standard library declares both sort, which takes an inout and sorts in-place, and sorted, which takes input by value and returns a freshly sorted array.

How to sub slice an interface{} that is a slice?

The datastore.GetMulti(c appengine.Context, key []*Key, dst interface{}) API allows me to get 1000 entities at most. I want to get more.
An obvious way to solve this generically is to create a wrapper function mypkg.GetMulti() which sub slices (key[0:1000], key[1000:2000]...) the original arguments and calls datastore.GetMulti() several times with them.
It's pretty clear how to sub slice key []*Key, but how do I sub slice dst interface{} which could be:
// dst must be a []S, []*S, []I or []P, for some struct type S, some interface
// type I, or some non-interface non-pointer type P such that P or *P
// implements PropertyLoadSaver. If an []I, each element must be a valid dst
// for Get: it must be a struct pointer or implement PropertyLoadSaver.
//
// As a special case, PropertyList is an invalid type for dst, even though a
// PropertyList is a slice of structs. It is treated as invalid to avoid being
// mistakenly passed when []PropertyList was intended.
Since you are the caller of datastore.GetMulti which takes an interface{} argument, you can provide any concrete value as that argument; it doesn't need to be converted to the empty-interface type beforehand. In other words, anything and everything implements the empty interface, so just pass that thing.
func GetMulti() {
mySlice := make([]Whatever, 3000, 3000)
for i := 0; i < 3; i++ {
subSlice := mySlice[i * 1000 : (i + 1) * 1000]
datastore.GetMulti(c,k, subSlice) // 'c' and 'k' assumed to be defined
}
}
In case mypkg.GetMulti should be a generic function, taking an interface{} value as well, then you'll have to use reflection as in the following example where instead of fmt.Println with the length of the subslice you'd call datastore.GetMulti with each subslice:
package main
import "fmt"
import "reflect"
func GetMulti(i interface{}) {
v := reflect.ValueOf(i)
if v.Kind() != reflect.Slice {
panic("argument not a slice")
}
l := v.Len()
p := (l / 1000)
for i := 0; i < p; i++ {
fmt.Println(v.Slice(i*1000, (i+1)*1000).Len())
}
fmt.Println(v.Slice(p*1000, l).Len())
}
func main() {
s := make([]int, 3560, 3560)
GetMulti(s)
}

Resources