-3

I'm working towards implementing a concurrent string and byte reader in Go. The purpose of this is to allow parsing of newline and other such bytes in the read strings.

In researching this problem I've found various ways of handling multiple values in a single value context 1, however none of these deal with the occurrence of mixed types. The idea of using an interface to deal with this has been suggested 2, and has been attempted, but I am uncomfortable with the lengthy verbosity of the exisitng suggestions 3 and 4.

I wonder if there is an idiomatic way to ectively sort through a variety of typed values in a tidy fashion.

EDITED: First I established an interface, as suggested. This seems a good idea, and is a commonly used trick from C if I recall.

func Use(vals ...interface{}) {
    i := 0
    p := []uint8{}  //I've replaced the alias "byte" with the native "uint8"
    var val uint8  //I've changed this declaration to a non-assigned declaration
    for i, val := range vals {
        if i < 1 {
            _ = val
            i++
        } else {
            p[i] = val.(uint8)
            return fmt.Print(p[i]) //please excuse the earlier typo
            //interestingly, this call to p[i] returns more than one value
        }
    }
}

The rest of the essential code follows:

func other() (string, []byte) {
    a := "declared and not used"
    b := []byte("stuff")
    return a,b
}

func main() {
    Use(other())
}

It remains unbeknownst to me why this code should appear to have multiple values inside p[i]. Shouldn't the blank identifier used in the control loop make such a possibility unlikely?

The new error, from the edited code is reported as: invalid type assertion: x.(uint8) (non-interface type func(...interface {}) []interface {} on left)

The original code can be found at: https://play.golang.org/p/BEhOT7R0vvr

The edited code can be found at: https://goplay.space/#SF7X7dx8yL9

gustable
  • 29
  • 1
  • 8

2 Answers2

1
        return fmt.print(p[i]) 
        //interestingly, this call to p[i] returns more than one value

No, it doesn't.

In fact, the compiler doesn't have any idea how many items it returns, because fmt.printf isn't exported, so it doesn't know what it is. All it knows is that it returns one or more values. But you're in a function with zero return values, thus the error.

It's unclear what you want, so I'm not sure how to suggest changing your code, but two potential answers seem obvious:

  1. Stop returning something:

        fmt.Print(p[i])
        return
    
  2. Change your function to return something, then call the proper function:

    func Use(vals ...interface{}) byte {
      // ... skip
          return p[i]
    
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
0

When you're calling Use(other()), you're passing two arguments to Use's variadic parameter: a string, and a []byte. So when you iterate over them, the first iteration gives you the string, the second iteration gives you the []byte. Also a lot of this code is unnecessary and should be failing (some at compile time, some at run time):

// this declares a variable in function scope that is never used; it's immediately shadowed
val := []byte("")
// this declares a *new* variable val in loop scope, shadowing the outer val
for i, val := range vals {
    if i < 1 {
        // this does absolutely nothing
        _ = val
        // this also does absolutely nothing - i is the loop iterator and is overwritten by range on every iteration
        i++
    } else {
        // this should be hard failing because there is no case where val is a byte; it's only ever string or []byte
        p[i] = val.(byte)
        // It's fmt.Print - fmt.print would be unexported and not usable
        return fmt.print(p[i])
    }
}
Adrian
  • 42,911
  • 6
  • 107
  • 99