type Developer struct {
Name string `json:"name"`
Skills []interface{} `json:"skills"`
}
This is my struct
var developers []Developer
var devData Developer
if searchResult.TotalHits() > 0 {
for _, hit := range searchResult.Hits.Hits {
err := json.Unmarshal(hit.Source, &devData)
if err != nil {
fmt.Println("error")
}
fmt.Println(devData.Skills) // utp here data are correct
developers = append(developers, devData)
}
//after loop data skills value are not correct
}
but when actual data is made the skills are same throught all arrays
expected : ['name' : 'John Doe','skills': ["php","go"]], ['name' : 'Rovvie Doe','skills': ["java","haskel]]
But output : ['name' : 'John Doe','skills': ["java","haskel"]], ['name' : 'Rovvie Doe','skills': ["java","haskel]]
You're reusing the same devData variable, and therefore its allocated memory, in each iteration of the for loop. This means that when you call json.Unmarshal and pass it the pointer to devData you're overwriting what has been written to that memory during the previous iteration.
Instead of declaring the devData variable above the if statment, you should declare it inside the for loop to get a new segment of memory allocated for each of your iteration variables.
Note that if the type of the variable is pointer-less then you could use your original approach since Go is pass-by-value and each time you pass a variable to a function, including append, a shallow copy of that variable's value gets created.
However, since slices in go do hold a pointer to the first element of the slice the Developer type, because of its Skills field, does not qualify.
And that is why you're seeing the Name field getting copied correctly, but the contents of the Skills field getting overwritten.
Related
I have an array of value pairs I want to modify. I need to add and remove values from this array as well, so I used a list. When I tried to use a list, I encountered an error.
Error CS1612 - Cannot modify the return value of 'List<(int, float)>.this[int]' because it is not a variable
So I decided I would investigate. I tried using an array instead, and it... worked fine? The following code only throws an error on arr1[0].Item1 += 1;.
static void Main()
{
List<(int, float)> arr1 = new List<(int, float)>() { (0, 0) };
(int, float)[] arr2 = new (int, float)[1];
arr1[0].Item1 += 1; // This line
arr2[0].Item1 += 1;
}
Why are tuple arrays mutable, but lists are not? Is this because arrays are simple blocks of data you can modify easily, but lists have a lot of backend behind them that complicates things? Is there a simple way to get around this, or am I going to have to make my own custom class?
Why are tuple arrays mutable, but lists are not?
The list itself is mutable, but not in the way you're doing it. Note that this isn't anything specific to tuples - it's just the case for any mutable struct.
The list indexer getter returns a value (i.e. a copy of the tuple in your case) - so modifying that value wouldn't modify the copy in the list. The compiler is trying to avoid you making a change to a value that's about to be thrown away. Array access doesn't do that - arr2[0] refers to the variable within the array. (An array is effectively a collection of variables.)
If you want to mutate the list, you can have to fetch the tuple, mutate it, then put it back:
var tuple = arr1[0];
tuple.Item1++;
arr1[0] = tuple;
Note that this also explains why you can't use list access expressions as arguments for ref parameters, but you can do the equivalent for arrays:
public void Method(ref int x) => x++;
public void CallMethod()
{
var list = new List<int> { 0 };
var array = new int[] { 0 };
Method(ref list[0]); // Error
Method(ref array[0]); // Valid
}
I am trying to allocate sprite data to a global array using preset indexes for the sprites. I am initializing the array as an array of SKSpriteNodes. I am sending SKSpriteNodes to this array, each sprite has a set index for this array. I realize I could also do this with a loop instead of setting indexes, but I want to figure out the array allocation first.
I have tried reserveCapacity(27) because there will be 27 sprites to pass in, but when I try I get an index out of range error.
class GameScene: SKScene
{
//main array that will be used to store sprite button data
var mainArr: [SKSpriteNode] = [SKSpriteNode]()
..
override func didMove(to view: SKView)
{
mainArr.reserveCapacity(27)
...
if let name = touchedNode.name
{
if name == "pea"
{
peaFlag = peaFlag * -1
manageArrayData(name: pea, nameFlag: peaFlag, nameIndex: peaInd)/*may need to add images*/
}
...}//end touchNode
...} //end didMoveTo
func manageArrayData(name: SKSpriteNode, nameFlag: Int, nameIndex: Int)
{
if nameFlag >= 0
{
print(nameFlag)
print(nameIndex)
print("in array")
mainArr.insert(name, at: nameIndex)
//dump(mainArr)
print("-=-=-=-in-=-=-=-")
}
as I said, the error is: Fatal error: Array index is out of range
2019-06-27 09:54:09.414271-0700 Select[36307:1432579] Fatal error: Array index is out of range
I believe the error is because reserveCapacity() is of type Int, while I am trying to allocate memory for SKSpriteNode... therefore there is no space for what I am allocating, hence the "out of range"
there are multiple "buttons" (using SKSpriteNodes), so I created an if tree for the buttons to fall under.
reserveCapacity does not create entries in the array. It just makes sure you won't need to perform a reallocation (and possible relocation) if you add that many entries. It's generally only needed for performance reasons. It won't change anything about how indexing works.
If you want empty entries in the array, you need to add them. See Array(repeating:count:) to create an array with some fixed values.
I am passing in a string array and an empty integer array into a function. The point of the function is to convert each element of the string array to an integer and store that into the integer array. When I print the integer array from within the function itself, everything is fine. However, when I try to print the integer array outside of the function, it prints an empty array.
employeeDataInt is the integer array, and employeeDataString is the string array.
I apologize if this is a dumb question but I am new to go. Thanks
package main
import (
"bufio"
"fmt"
"log"
"os"
"strconv"
"strings"
)
func strToInt(employeeDataString []string, emplyoeeDataInt []int) []int {
for _, i := range employeeDataString[2:] {
j, err := strconv.Atoi(i)
if err != nil {
panic(err)
}
employeeDataInt = append(employeeDataInt, j)
fmt.Println(employeeDataInt) //this prints out the appropriate array
}
return employeeDataInt
}
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter file name: ")
fileName, err := reader.ReadString('\n')
if err != nil {
log.Fatalf("failed opening file: %s", err)
}
fileName = strings.TrimSuffix(fileName, "\n")
file, err := os.Open(fileName)
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var employeeLine []string
for scanner.Scan() {
employeeLine = append(employeeLine, scanner.Text())
}
file.Close()
var employeeDataString = []int{}
for _, employee := range employeeLine {
employeeDataString := strings.Split(employee, " ")
strToInt(employeeDataString, employeeDataInt)
fmt.Println(playerData2) //this is outputting just `[]`
}
}
You aren't taking the value of the array and thus the Slice you passed into the function might or might not be updated correctly.
strToInt(employeeDataString, employeeDataInt)
// should be
employeeDataInt = strToInt(employeeDataString, employeeDataInt)
And while at it, you are never assigning playerData2. So fmt.Println(playerData2) will always be [].
But aside from that there are some subtle issues with your usage of Arrays/Slices here:
First the difference between Slices and Arrays:
Go does not allow you to directly work with Arrays.
Unless they have a fixed length ([3]int{} or []int{1,2,3]) you aren't actually looking at an array but at a Slice ([]int).
The slice is just a pointer to an array (along with it's capacity and some other info) and it essentially allows Go to safely muck around with arrays because you never grow an existing array (the size of an array is fixed at initialization). So you can never append to an array.
What Go does to give you the illusion of appending to an array is having a larger than required underlying array, and the Slice controls the access to that array. So if the underlying array has a capacity of 5 and you already stored 3 items in it you can do 2 append operations without having to allocate a new array and copy the existing array elements to the new memory location.
So when you are passing a []int you are actually passing an array pointer (by value) around.
This leads to the next gotcha in your code: The use of append.
As mentioned above, append takes a Slice, looks at the underlying array and how much space is actually left and then adds to it or allocates a new array. If a new array is allocated append returns a new slice that points to the new array.
So calling:
foo := []{1,2,3}
append(foo, 4)
append(foo, 5)
append(foo, 6)
fmt.Print(foo)
// => might return 1,2,3,4,5
You always have to take the return value of append otherwise you risk still referencing the "old" slice that didn't get the new items appended.
So the correct way to grow a Slice, or work with Slices in general is to keep in mind that: Slices are passed by value, so always keep updating your variables with the return values of Slice modifying functions.
There are a few issues in your code:
You're discarding the return value of strToInt.
You're trying to utilize employeeDataInt in main but it is undefined there (which should be causing a compile error, not a runtime issue).
You're declaring employeeDataString twice, in two different scopes in main (inside and outside the for loop), with two different types ([]string and []int). The outer-scoped variable is unused, so should also be causing a compile error.
You're printing playerData2 which is never defined or used - again, this should be causing a compiler error, not incorrect behavior.
Given there were compile errors in the code, either some crucial code was missing from your post, or you did not notice/mention the compile errors.
The correct code within main would be:
var employeeDataInt []int // Seems like you just have the wrong variable name here
for _, employee := range employeeLine {
employeeDataString := strings.Split(employee, " ")
// You're missing the assignment here
employeeDataInt = strToInt(employeeDataString, employeeDataInt)
fmt.Println(employeeDataInt) // This was referencing the wrong variable
}
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.
I have these two functions where i am trying to modify the elements. One of them compiles and other says 'val cannot be reassigned'. What is the difference between the following functions? Why does one compile and the other does not?
The one that compiles
fun <T> Array<T>.mapInPlace2(transform: (T) -> T) {
for (i in this.indices) {
this[i] = transform(this[i])
}
}
The one that says
Val cannot be reassigned
fun <T> Array<T>.mapInPlace1(transform: (T) -> T) {
for (i in this) {
i = transform(i);
}
}
Similiarly to how function parameters are final in Kotlin, so are the variables used in for loops. Essentially, writing down...
for (i in array) {
...
}
... is the equivalent of doing this in Java:
for (final int i : array) {
...
}
This helps catch some common errors, in this case - if the compiler allowed you - you'd be reassigning this local variable that just contains a reference to the real element, without changing the array. In Java terms, you'd be doing this:
for (int i : array) {
i = transform(i);
}
This new value of i is unused, it doesn't change the array itself, and it will be immediately overwritten by the value of the next element when the loop comes around.
Try this:
for(i:Int in 0 until this.size) {
this[i] = "your value"
}
You're confusing the mutability of references to objects and objects themselves.
In the first example, the structure is mutable, but the reference to it is immutable. You can change the structure of the object itself, but you can't change what structure the references points to.
In the second example, you're trying to change an immutable reference to an object, not the object itself.
If you write
val i = obj
obj can still be mutated if it's a mutable object. i can't be reassigned though, sine the reference can't be changed.