Value of map retrieval - go

When you print the result of a function with 2 return values, you will get
valA valB
Retrieving from a map can return either 1 value or two values:
v := m["Answer"]
v, ok := m["Answer"]
However, when you print m["Answer"], you will always only print v. What exactly is the "function signature" of a map retrieval? Or is this just a special case? Here is an example showing the distinction:
package main
import "fmt"
func main() {
m := make(map[string]int)
m["Answer"] = 42
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present:", ok)
fmt.Println(banana())
fmt.Println(m["Answer"])
}
func banana() (int, int) {
return 1, 2
}

Special case. The same applies to other operations, among others:
read from chan:
v, ok := <- somechannel
casting, e.g.:
casted, ok := somevar.(sometype)

Related

Is it possible to infer type parameters from what return values are assigned to?

Suppose I wrote two functions like this:
func ToInterfaceSlice[T any](s []T) []interface{} {
res := make([]interface{}, len(s))
for i, v := range s {
res[i] = v
}
return res
}
func FromInterfaceSlice[T any](s []interface{}) (res []T, err error) {
res = make([]T, len(s))
for i, v := range s {
vt, ok := v.(T)
if !ok {
return nil, fmt.Errorf("%v (type=%T) doesn't fit the target type %T", v, v, res)
}
res[i] = vt
}
return
}
When I parse type from the input parameters, I can simply use
var m = []int{1, 2, 3}
fmt.Println(ToInterfaceSlice(m))
The compiler knows the T is int.
However when I try passing type from the return variables
var m []int
m, _ = FromInterfaceSlice([]interface{}{1, 2, 3})
fmt.Println(m)
The compiler gives error:
.\scratch.go:29:27: cannot infer T
I must explicitly pass the type in the function call:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
fmt.Println(m)
Is there anything hard to infer type parameters from return type when the receiver vars are not interface? Or just not implemented, even not to implement on purpose?
Update #1 after the comment
I do know a, b := GenericFunc() cannot refer the type of returned value. Currently Go does have "it depends" case whether requires the explicit instantiation or not from the user input.
type Set[T comparable] map[T]struct{}
func NewSet[T comparable](eles ...T) Set[T] {
s := make(Set[T])
for _, ele := range eles {
s[ele] = struct{}{}
}
return s
}
It's okay to use both t := NewSet(1, 2, 3) and t := NewSet[string](), but not var t NewSet[float64] = NewSet() now because of this
The current rules for type inference are explicit. How the return values are used is not taken into account:
Type inference is based on
a type parameter list
a substitution map M initialized with the known type arguments, if any
a (possibly empty) list of ordinary function arguments (in case of a function call only)
As of Go 1.18 might simply rewrite your function to accept an argument of the required type; this has also the benefit of not hiding allocations inside the function body:
func FromInterfaceSlice[T any](s []interface{}, dst []T) error {
if len(s) != len(dst) {
return errors.New("lengths don't match")
}
for i, v := range s {
vt, ok := v.(T)
if !ok {
return nil, fmt.Errorf("%v (type=%T) doesn't fit the target type %T", v, v, res)
}
dst[i] = vt
}
return nil
}
And pass in a destination slice with the required length:
func main() {
src := []interface{}{1, 2, 3}
m := make([]int, len(src))
_ = FromInterfaceSlice(src, m)
fmt.Println(m)
}
If you can't or don't want to determine the slice's length beforehand, you are left with explicit instantiation:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
// ^^^ explicit type argument
Also the type parameters are still not inferrable with := shorthand declaration:
// what is m???
m, err := FromInterfaceSlice([]interface{}{1, 2, 3})

What does the underscore(_) do in for loop Golang?

I am just getting started learning the Golang language!
In for loop, I saw sometimes adding an underscore or without underscore.
Whatever add _ or not, I got the same result.
package main
import (
"fmt"
)
func main() {
doSomething()
sum := addValues(5, 8)
fmt.Println("The sum is", sum)
multiSum, multiCount := addAllValues(4, 7, 9)
fmt.Println("multisum", multiSum)
fmt.Println("multiCount", multiCount)
}
func doSomething() {
fmt.Println("Doing Something")
}
func addValues(value1 int, value2 int) int {
return value1 + value2
}
func addAllValues(values ...int) (int, int) {
total := 0
for _, v := range values {
total += v
}
return total, len(values)
}
func addAllValues(values ...int) (int, int) {
total := 0
for v := range values {
total += v
}
return total, len(values)
}
All I know is I don't care about the index. Is that all? or there is something more what I have to know??
I really appreciate your help!
For range over slices:
In for v := range values { the v is the index of the element in the slice.
In for _, v := range values { the v is the actual element value.
In for i, v := range values { the i is the index and the v is the element.
In for i, _ := range values { the i is the index of the element in the slice.
You can run this playground example to see the differences.
Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
string s string type index i int see below rune
map m map[K]V key k K m[k] V
channel c chan E, <-chan E element e E
For more details see the spec.
If you don't want to use the variable that iterates in the loop, you can use _ to simply let Go ignore it:
mySlice := [int]{1,3,4,59,5}
for _,x := range mySlice {
fmt.Println(x)
}
By placing underscore you are telling the compiler this:
Ok, I'm aware that this function is returning something but I don't care! For example:
package main
import "fmt"
func main() {
mul1, add1 := test_function(2, 3)
fmt.Println(mul1, add1)
mul2, _ := test_function(4, 5)
fmt.Println(mul2)
_, add3 := test_function(7, 8)
fmt.Println(add3)
}
func test_function(a int, b int) (mul int, add int) {
return a * b, a + b
}
just to add to the amazing answer above:
I think one of the main benefits is to maintain readability in your program: if you replace the blank identifier with a variable then you have to use it or your program will not compile.
also this decrease memory allocation be neglecting one of the returned parameters...

Golang - Sum of an [...]interface{}

I have created a generic data structure, with a name and a generic array in Golang.
package main
import "fmt"
type NamedArray struct {
Name string
values []interface{}
}
func main() {
data := [...]int{1, 2, 3, 4, 5}
interfaced_data := make([]interface{}, len(data))
for i, v := range data{
interfaced_data[i] = v
}
int_arr := NamedArray{Name: "Int Array", values: interfaced_data}
fmt.Println(int_arr)
// fmt.Println(int_arr.Sum()) -- uncomment to run Sum
data_float := [...]float64{0.1, 0.2, 0.3, 0.4, 0.5}
interfaced_data_float := make([]interface{}, len(data_float))
for i, v := range data_float{
interfaced_data_float[i] = v
}
float_arr := NamedArray{Name: "Float Array", values: interfaced_data_float}
fmt.Println(float_arr)
// fmt.Println(int_arr.Sum()) -- uncomment to run Sum
}
Now I want to define a method which allows me to sum all the values in the array. I know that they are numeric (though whether they are int or float is dependant on context) but I am having some serious trouble.
func (arr NamedArray) Sum() interface{} {
data := arr.values
sum := 0
for i, v := range data {
sum += v
}
return sum
}
I can't seem to make this work, though. When I uncomment lines 18 and 27 (fmt.Println(int_arr.Sum() and fmt.Println(int_arr.Sum()) and try to run the code I get
34:9: invalid operation: sum += v (mismatched types int and interface {})
During compilation.
Does anyone know how to add generic types, given we know that they are numeric?
Thanks!
The + operator is not defined on values of type interface{}. You have to get a value of type int out of the interface{} values before you can work with it as a number.
For that, you may use type assertion. See this example:
s := []interface{}{1, 2, 3, "invalid"}
sum := 0
for _, v := range s {
if i, ok := v.(int); ok {
sum += i
} else {
fmt.Println("Not int:", v)
}
}
fmt.Println("Sum:", sum)
Output (try it on the Go Playground):
Not int: invalid
Sum: 6
The above example only handles int numbers, and nothing else. If you want to "support" multiple number types, a more convenient way would be to use a type switch:
s := []interface{}{1, int32(2), int8(3), "invalid"}
sum := 0
for _, v := range s {
switch i := v.(type) {
case int:
sum += i
case int32:
sum += int(i)
case int8:
sum += int(i)
default:
fmt.Println("Not int:", v)
}
}
fmt.Println("Sum:", sum)
Output is the same. Try this one on the Go Playground.

Simple mapReduce operation on strings

I have a list of strings
elems := [n]string{...}
I want to perform a simple mapReduce operation, such that I
Map every string to a different string, let's say string -> $string
Reduce all the strings to one string with a separator, e.g. {s1, s2, s3} -> s1#s2#s3
all in all: {s1, s2, s3} -> $s1#$s2#$s3
What's the best way to do this?
I'm looking for efficiency and readability
Bonus points if it's generic enough to work not only on strings
For mapping just a list, you won't have much choice other than to go over each string. If the transform algo is time-consuming and you need speed, you can consider splitting the job and use a go routine. Finally you can use the strings.Join function which has an option to specify a separator, this normally performs the reduce part efficiently. The size of the dataset can also be a consideration, and for larger sized lists you may want to compare performance with strings.Join and your own customized algo and see if you want to use multiple go routines/channels to achieve what you want to.
If you don't need to do the 2 things separately, the end result can be achieved simply by using strings.Join():
package main
import (
"fmt"
"strings"
)
func main() {
a := []string{"a", "b", "c"}
p := "$"
fmt.Println(p + strings.Join(a[:], "#"+p))
}
prints $a#$b#$c
playground
Go is explicitly NOT a functional programming language.
You map and reduce using a for loop.
a := []string{"a", "b", "c"}
result := "initvalue"
for n, i := range a {
result += i + string(n)
}
If you are not going to perform any sort of IO operations inside your map functions (means they are doing just some computations), making it concurrent would make it slower for sure and even if you are doing some IO, you should benchmark. Concurrency would not make things faster necessarily and some times add unnecessary complications. In many cases just a simple for loop is sufficient.
If the map functions here are IO bound or are doing some sort of computation heavy calculations that do benefit from going concurrent, solutions can vary. For example NATS can be used to go beyond one machine and distribute the workload.
This is a relatively simple sample. Reduce phase is not multistage and is blocking:
import (
"fmt"
"strings"
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
type elem struct {
index int
value interface{}
}
func feed(elems []interface{}) <-chan elem {
result := make(chan elem)
go func() {
for k, v := range elems {
e := elem{
index: k,
value: v,
}
result <- e
}
close(result)
}()
return result
}
func mapf(
input <-chan elem,
mapFunc func(elem) elem) <-chan elem {
result := make(chan elem)
go func() {
for e := range input {
eres := mapFunc(e)
result <- eres
}
close(result)
}()
return result
}
// is blocking
func reducef(
input <-chan elem,
reduceFunc func([]interface{}) interface{}) interface{} {
buffer := make(map[int]interface{})
l := 0
for v := range input {
buffer[v.index] = v.value
if v.index > l {
l = v.index
}
}
data := make([]interface{}, l+1)
for k, v := range buffer {
data[k] = v
}
return reduceFunc(data)
}
func fanOutIn(
elemFeed <-chan elem,
mapFunc func(elem) elem, mapCount int,
reduceFunc func([]interface{}) interface{}) interface{} {
MR := make(chan elem)
wg := &sync.WaitGroup{}
for i := 0; i < mapCount; i++ {
mapResult := mapf(elemFeed, mapFunc)
wg.Add(1)
go func() {
defer wg.Done()
for v := range mapResult {
MR <- v
}
}()
}
go func() {
wg.Wait()
close(MR)
}()
return reducef(MR, reduceFunc)
}
func Test01(t *testing.T) {
elemFeed := feed([]interface{}{1, 2, 3})
finalResult := fanOutIn(
elemFeed,
func(e elem) elem {
return elem{
index: e.index,
value: fmt.Sprintf("[%v]", e.value),
}
},
3,
func(sl []interface{}) interface{} {
strRes := make([]string, len(sl))
for k, v := range sl {
strRes[k] = v.(string)
}
return strings.Join(strRes, ":")
})
assert.Equal(t, "[1]:[2]:[3]", finalResult)
}
And since it uses interface{} as the element type, it can get generalized.

How to read an slice of like []interface{} in Go?

I have something like this:
a := []interface{}{}
b := []interface{}{}
type S struct {
text string
}
s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a := append(a, b)
a
And now I want to read elements of a, or elements of elements.. but how?
What you want is called a type assertion. http://golang.org/ref/spec#Type_assertions
The simple example on that page is:
var x interface{} = 7 // x has dynamic type int and value 7
i := x.(int) // i has type int and value 7`
The other thing to note is that a type assertion returns a value called ok that is true if the assertion is successful. Here's a simple code example for your case:
a := []interface{}{}
b := []interface{}{}
type S struct {
text string
}
s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a = append(a, b)
assertedS,ok := a[0].(S)
if !ok { // If this is, in fact, not a value of type S, something is wrong
// error handling
}
fmt.Println(assertedS) // Should show you the same thing as printing s
assertedB,ok := a[1].([]interface{})
if !ok {
//...
}
assertedT,ok := assertedB[0].(S)
if !ok {
//...
}
fmt.Println(assertedT) // Should show you the same thing as printing t
If you don't know ahead of time which list element is what, you can iterate through it and use the "type switch". http://golang.org/ref/spec#Switch_statements
switch x.(type) {
// cases
}
Which allows you to perform conditional behavior based on what type the stored interface{} really is.
For instance, you might use
func ExtractSlice(a []interface{}) {
for _,x := range a {
switch i := x.(type) {
case S:
fmt.Println(i)
case []interface{}:
ExtractSlice(i) // Recursively unpacks b once it's found within a
}
}
}
Do you mean this?
a := []interface{}{}
b := []interface{}{}
type S struct {
text string
}
s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a = append(a, b)
for _, v := range a {
switch v.(type) {
case S:
fmt.Println("S", v)
default:
fmt.Println("Slice", v)
}
}
This code example may help:
package main
import "fmt"
func main() {
a := []interface{}{}
b := []interface{}{}
type S struct {
text string
}
s := S{"string s"}
t := S{"string t"}
a = append(a, s)
b = append(b, t)
a = append(a, b)
for _, v := range a {
fmt.Println(v)
}
}
but be aware that you've defined a and b as slices of interfaces. This means, that when you do a = append(a, b) you're putting the b slice after the existing a string in the a slice, and therefore when you range over a you get:
{string s} //interface of string
[{string t}] //slice of interface of string

Resources