Initialize multiple values in a struct using one function - go

I would like to initialize multiple variables in a struct using the same function like so:
type temp struct {
i int
k int
}
func newtemp(age int) *temp{
return &temp{
i, k := initializer(age)
}
}
func initializer(age int)(int, int){
return age * 2, age * 3
}
however, I can not due to having to use : to initialize variables when creating a struct, is there any way I can do something that is valid yet like the code above?

Using composite literal you can't.
Using tuple assignment you can:
func newtemp(age int) *temp{
t := temp{}
t.i, t.k = initializer(age)
return &t
}
Testing it:
p := newtemp(2)
fmt.Println(p)
Output (try it on the Go Playground):
&{4 6}

Related

How to add new elements of a slice automatically to function parameter as slice grows

Is there a way to doing this automatically ?
package main
import "fmt"
func main() {
var a []string
a = append(a, "this", "this2", "this3")
increaseArguments(a)
a = append(a, "this4")
increaseArguments(a)
}
func increaseArguments(b []string) {
// I want, when i add new element to slice i want this function act as this
// fmt.Println(b[0],b[1], b[2], b[3])
fmt.Println(b[0], b[1], b[2])
}
Instead of adding b[3] as argument to fmt.Println is there a way to add it automatically ?
Note that if b would be of type []any, you could pass it as the value of the variadic parameter of fmt.Println():
fmt.Println(b...)
But since b is of type []string, you can't.
But if you transform b into a []any slice, you can. You can use this helper function to do it:
func convert[T any](x []T) []any {
r := make([]any, len(x))
for i, v := range x {
r[i] = v
}
return r
}
And then:
func increaseArguments(b []string) {
fmt.Println(convert(b)...)
}
This will output (try it on the Go Playground):
this this2 this3
this this2 this3 this4
Note: creating a new slice in convert() will not make this solution any slower, because passing values explicitly (like fmt.Println(b[0], b[1], b[2])) also implicitly creates a slice.
See related question: How to pass multiple return values to a variadic function?

How to make variable type slices

I was learning go by doing some of the problems I have already completed in other languages.
So one of the problem was:-
Find the sum of the elements in Array
Arr = [1,2,[7,8,3],1,[3,[2,[4,5]],6]]
I have tried making an interface type array but that also didn't work
func ProdSum(prods interface{},sum int ,depth int){
for id,val:=range prods{
if isArray(val){
ProdSum(val,sum,depth)
}
}
}
type arr []interface{}
func main(){
arra:=arr{5,2,arr{7,-1},3,arr{6,arr{-13,8},4}}
ProdSum(arra,0,1)
}
Error :
./prodsum.go:16:14: cannot range over prods (type interface {})
Use a type assertion or type switch to determine if a value is a slice or an integer. Here's how to do it using a type switch:
func sum(value interface{}) int {
switch value := value.(type) {
case arr:
var result int
for _, v := range value {
result += sum(v)
}
return result
case int:
return value
default:
panic("type not handled")
}
}
Call it like this:
a := arr{5, 2, arr{7, -1}, 3, arr{6, arr{-13, 8}, 4}}
n := sum(a)
Run it on the playground.
The way you are declaring and initializing the array is correct, although you don't need the arr type.
Without the arr type it will look like this:
Running in Go Playground
myArr := []interface{}{1, 2, []int{7, 8, 3}, 1, []interface{}{3, []interface{}{2, []int{4, 5}}, 6}}
Now, the specific error you are seeing is not related to your slice declaration. It is related to the function signature of ProdSum.
ProdSum takes an argument of type interface{}- which is not a slice so you cannot iterate over it. You want the argument to have a type of []interface{} (slice of empty interface):
func ProdSum(prods []interface{}, sum int, depth int) {
for itr, prod := range prods {
// prod has type: interface{}
}
}
Keep in mind that you will need to do type assertions when reading the values out of the slice and summing them. You can't add an interface{} to anything because (before an assertion to int) Go doesn't recognize it as a number.

How to delete different type of slice using only 1 methods

I have 2 go functions like following
func removeL2McEntry(a []api.L2McEntry, index int) []api.L2McEntry {
a = append(a[:index], a[index+1:]...)
element
return a[:len(a)]
}
func removeVlagBasedGroup(a []api.VlanPortBased, index int) []api.VlanPortBased {
a = append(a[:index], a[index+1:]...)
return a[:len(a)]
}
As you can see, both functions are doing the same work. But I need to separate them because the outputs and the inputs of the functions are different type.
I have tried:
func removeSlice(a interface{}, idx int) interface{} {
switch v := a.(type) {
case []string:
v = append(v[:idx], v[idx+1:]...)
fmt.Println("is ary", v)
return v[:len(v)]
case []int:
v = append(v[:idx], v[idx+1:]...)
fmt.Println("is ary", v)
return v[:len(v)]
default:
}
return nil
}
But there is too many repetitive code in this way.
Is there any way to make it just one function and reduce the repetitive code?
Thanks in advance.
As Adrian noted, removing an element from a slice is one line of code, in general:
a = append(a[:i], a[i+1]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]
It's not really worth writing a function for it, just use this code snippet where needed.
If you do need to create a function that can handle any slice types, it can be created using reflection. But when using it, you will have to use a type assertion on the result, as the function can only return a static type of interface{}. It will also be slower than using the above snippet on your concrete slice value!
The above remove steps can be "reproduced" using the reflect package. Slicing is the Value.Slice() method, and the append operation is the reflect.AppendSlice() function.
This is how it could look like (types and bound checks omitted):
func remove(s interface{}, i int) interface{} {
v := reflect.ValueOf(s)
return reflect.AppendSlice(v.Slice(0, i), v.Slice(i+1, v.Len())).Interface()
}
Testing it:
is := []int{0, 1, 2, 3}
is = remove(is, 2).([]int)
fmt.Printf("%#v\n", is)
ss := []string{"0", "1", "2", "3"}
ss = remove(ss, 2).([]string)
fmt.Printf("%#v\n", ss)
Output (try it on the Go Playground):
[]int{0, 1, 3}
[]string{"0", "1", "3"}
But again: I don't advise anyone to use this (although working) code, just remove the element directly with the original snippet.

How to write a pop() function

a := []int{1,2,3}
x, a := a[len(a)-1], a[:len(a)-1]
fmt.Println(a,x)
How to create a pop() function that will do the same for any type of an array?
Here is what I came up with so far:
func pop(a []*interface{}) interface{}{
x := a[len(a)-1]
a = a[:len(a)-1]
return x
}
func main(){
a := []int{1,2,3}
x = pop(a)
fmt.Println(a,x) // -> [1,2] 3
}
But I get cannot use a (type []int) as type []interface {}or other error messages if I try to tweak the code by trial and error.
package main
import (
"fmt"
"reflect"
)
func pop(a interface{}) interface{} {
v := reflect.ValueOf(a).Elem()
x := v.Index(v.Len() - 1)
v.SetLen(v.Len() - 1)
return x
}
func main() {
a := []int{1, 2, 3}
x := pop(&a)
fmt.Println(a, x) // -> [1,2] 3
}
Though this can be implemented, I still think that x, a = a[len(a)-1], a[:len(a)-1] should be better than a pop function.
The go type system doesn't allow you to cast from []type1 -> []type2. Even if it did interfaces are a struct containing a type id and pointer to the object, where normally you would just have the object. Because of this you need to take a interface{} and use reflect to do the slicing.
func pop(slice interface{}) (interface{}, interface{}) {
v := reflect.ValueOf(slice)
return v.Slice(0,v.Len()-1).Interface(), v.Index(v.Len()-1).Interface()
}
Go Playground
Note that this loses compile time type safety, because it must use an interface. Additionally, due to using interfaces the poped value may be allocated, creating extra GC pressure.
Common Go style typically recommends not writing a function like this, and just inlining the small amount of code manually.
After all that really good anwers using reflection I also want to add one answer which offers a more idiomatic Go solution. Like Rob Pike said in his great talk about Go Proverbs
interface{} says nothing
Reflection is never clear
So there should be also one answer showing the idiomatic Go way. This solution does not work for slices of standard types. But there the answer of cshu shows the best solution: x, a = a[len(a)-1], a[:len(a)-1]
For own defined types we have to define a Poper interface and the Pop function takes that as input and returns an empty interface.
type Poper interface {
Pop() interface{}
}
type MyType struct {
a []int
}
func (mt *MyType) Pop() interface{} {
x := mt.a[len(mt.a)-1]
mt.a = mt.a[:len(mt.a)-1]
return x
}
func Pop(p Poper) interface{} {
return p.Pop()
}
func main() {
a := &MyType{[]int{1, 2, 3}}
fmt.Println(Pop(a), a)
}
https://play.golang.org/p/UbDkoVYSMA
At all it is not a good idea to return an empty interface, because all following code has to support the interface{}.
The following code example does not work:
func main() {
a := &MyType{[]int{1, 2, 3}}
fmt.Println(Pop(a), a)
var b int
b = Pop(a)
}
https://play.golang.org/p/wg9__O44A8
The error says everything about that problem: cannot use Pop(a) (type interface {}) as type int in assignment: need type assertion
So the Pop() function does work by returning interface{} but the rest of the code using the result of that function needs to make a type assertion. So if you can avoid it you should search for another solution using types.

How do I declare a function pointer to a method in Go

I am trying to create function pointer to a function that has a method receiver. However, I can't figure out how to get it to work (if it is possible)?
Essentially, I have the following:
type Foo struct {...}
func (T Foo) Bar bool {
...
}
type BarFunc (Foo) func() bool // Does not work.
The last line of the code gives the error
syntax error: unexpected func, expecting semicolon or newline
If you want to create a function pointer to a method, you have two ways. The first is essentially turning a method with one argument into a function with two:
type Summable int
func (s Summable) Add(n int) int {
return s+n
}
var f func(s Summable, n int) int = (Summable).Add
// ...
fmt.Println(f(1, 2))
The second way will "bind" the value of s (at the time of evaluation) to the Summable receiver method Add, and then assign it to the variable f:
s := Summable(1)
var f func(n int) int = s.Add
fmt.Println(f(2))
Playground: http://play.golang.org/p/ctovxsFV2z.
Any changes to s after f is assigned will have no affect on the result: https://play.golang.org/p/UhPdYW5wUOP
And for an example more familiar to those of us used to a typedef in C for function pointers:
package main
import "fmt"
type DyadicMath func (int, int) int // your function pointer type
func doAdd(one int, two int) (ret int) {
ret = one + two;
return
}
func Work(input []int, addthis int, workfunc DyadicMath) {
for _, val := range input {
fmt.Println("--> ",workfunc(val, addthis))
}
}
func main() {
stuff := []int{ 1,2,3,4,5 }
Work(stuff,10,doAdd)
doMult := func (one int, two int) (ret int) {
ret = one * two;
return
}
Work(stuff,10,doMult)
}
https://play.golang.org/p/G5xzJXLexc
I am very likely off-target (just started on Golang) but what if you create a pointer then examine type:
pfun := Bar
fmt.Println("type of pfun is:", reflect.TypeOf(pfun))
then it seems that you can declare the type of pointer correctly:
https://play.golang.org/p/SV8W0J9JDuQ

Resources