-2

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 `[]`

    }
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • 1
    Assign the return value from `strToInt ` to `employeeDataInt`. Otherwise, the updated slice is ignored. – Charlie Tumahai Mar 12 '19 at 04:29
  • do you mean instead of just having `int[]` as my return, have `employeeDataInt int[]`? cause i tried that earlier and it gave me `missing function body` and `syntax error: unexpected [ after top level declaration` errors @ThunderCat – learningunix717 Mar 12 '19 at 04:31
  • 4
    The function returns a value, but the calling function ignores it. Fix with `employeeDataInt = strToInt(employeeDataString, employeeDataInt)`. Also, update the question with an [mcve]. The variable `playerData2` is not declared or set in the program. – Charlie Tumahai Mar 12 '19 at 06:28

2 Answers2

2

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.

Tigraine
  • 23,358
  • 11
  • 65
  • 110
  • 1
    Re-read the post - `strToInt` is correctly using the return value of `append`. The problem is that where it is called is discarding the return value of `strToInt`. – Adrian Mar 12 '19 at 13:37
  • I know :) But it's essentially the same issue (and append was meant as a example). `[]int` is a slice that is passed by reference, doesn't matter it's passed to `append` or `strToInt` – Tigraine Mar 13 '19 at 10:12
  • There is no pass by reference in Go. – Adrian Mar 13 '19 at 13:29
  • It's just so explicit in the language that you wouldn't consider it a traditional pass by reference: Pointers :) – Tigraine Mar 14 '19 at 11:57
  • But the issue is because it is *not* passed by pointer *or* by reference. It's passed by value. They share the same underlying array, until the underlying array is changed by `append`. – Adrian Mar 14 '19 at 12:53
0

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

}
Adrian
  • 42,911
  • 6
  • 107
  • 99