Function with two generic types - go

I want to write a generic function that looks like this:
func Transform(a A) B
... where both A and B are generic types.
If I only had a single generic type, I could do like this:
func Transform[A SomeType | SomeOtherType](a A) B
But how can I also define the B type?
This does not work:
func Transform[A SomeType | SomeOtherType][B SomeThirdType](a A) B

What do you do when you have multiple parameters for a function? You list them separated by comma. What do you do when a function has multiple type parameters? Yes, you list them separated by comma:
func Transform[A SomeType | SomeOtherType, B SomeThirdType](a A) B
This is detailed in Spec: Type parameter declarations:
TypeParameters = "[" TypeParamList [ "," ] "]" .

Related

Infer struct structure

I am using this to create a struct without defining a separate type:
data := struct {
Product *domain.UserProduct
Options *[]domain.UserProductOption
}{
Product: userProduct,
Options: userProductOptions,
}
Is there a way to do the same without defining struct's structure, as number of fields and their types can inferred? Something like:
data := {
Product: userProduct,
Options: userProductOptions,
}
As of Go 1.17 there's nothing like that to infer the type of a struct.
There's been some discussion of this in the proposal #35304, but it's still open. To summarize the discussion:
foo({x: y}) - unreadable
data := _{x: y} - unreadable (?)
data := struct {x: y} - overloads the syntax of struct
data := tuple {x: y} - new keyword
. . .
You're welcome to participate in the discussion and/or submit your own proposal.
I would think something like data := struct _ {X: x, Y: y} should be the most in line with the philosophy of _ being used to omit things (as in this case we want to omit the struct definition).
Is there a way to do the same without defining struct's structure
No. The language doesn't allow it: in Composite literals, it is defined how these work:
Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated. They consist of the type of the literal followed by a brace-bound list of elements. Each element may optionally be preceded by a corresponding key.
CompositeLit = LiteralType LiteralValue .
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
SliceType | MapType | TypeName .
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
The place where you can have the literal value is in an element list:
// the struct type may be defined or literal
// defined type
type User struct {
Name string
}
// `{"John"}` is the literal value
foo := []User{{"John"}}
// literal type
// `{"John","john#myself.com"}` is the literal value
bar := []struct{Name string; Email string}{{"John","john#myself.com"}}

testing function calling using var declaration to mock the result

I'm testing a function which called another function in Go. And here's what I have
package b
type b struct {...}
func (b *b) functionB(){...}
package a
import "b"
type a struct {...}
func (a *a) functionA() {
b := b{...}
b.functionB()
...
}
I want to modify the function declaration in b like this:
package b
type b struct {...}
var functionB = b.FuncInB
func (b *b) FuncInB(){...}
so that I can mock the return of functionB in a. However, I got error message in a that says b.functionB is undefined because it should be the function of b object. How can I make this work?
If you want to use a definition of one package in another package you have to export it. This is done by letting the definition start with a capital letter. Your type should be defined like this:
type B struct {...}
You cannot access a function via its type. This line
var functionB = b.FuncInB
will not work, as you can refer to the function only from an existing struct. You shoule remove this line and call it differently (see below).
Your package a has now two minor issues. When you want to use struct B from package b you have to either refer to it like this b.B
import "b"
b.B{...}
or make a dot import for package b:
import . "b"
B{...}
The last thing is, that you shadow the package name when assigning a variable with the same name as the package. In that, you should use a different variable name:
func (a *a) functionA() {
myB := b{...}
myB.FunctionB()
...
}
So in the end, your packages should look like this:
package b
type B struct {
// ...
}
func (b *B) FuncInB() {
// ...
}
package a
import "b"
type a struct {
// ...
}
func (a *a) functionA () {
myB := B {
// ...
}
myB.functionB()
// ...
}

Function which modifies any structure which has particular fields

I have a couple of structures, which inherit some basic structure. Something like this:
type s1 struct {
a string `json:"a"`
b string `json:"b"`
}
type s2 struct {
s1
c string `json:"c"`
d string `json:"d"`
}
type s3 struct {
s1
c string `json:"c"`
d string `json:"d"`
e string `json:"d"`
f string `json:"d"`
}
Now I need to define a function which operates on any structure which has fields a, b. Something like
func modifyStruct(s *s1) {
s.a, s.b = s.b, s.a
}
But has to work on s2, s3 and any other structure which inherits s1. I am trying to achieve this with an interface but so far with no luck. Any way to achieve this? The template is on go-playground.
The general solution is using reflection as shown in Cerise Limón's answer. The cons of using reflection is that you have to export the fields, and that it's slower than it should or could be.
In your example although it is completely fine and sufficient for the function to take a value of type *s1, as all types that embed s1 has a value of s1 (explicitly). The unqualified type name (without package name) acts as the field name for embedded fields:
s2 := s2{s1: s1{"A", "B"}}
fmt.Println(s2)
modifyStruct(&s2.s1)
fmt.Println(s2)
Output (try it on the Go Playground):
{{A B} }
{{B A} }
If you still want it to accept values of "any" (certain) types (so you don't have to refer to the embedded s1 field), but don't want to export the fields, then you may use interfaces for this. Using interfaces you keep the good parts of both solutions (remains fast, flexible and you do not have to export the fields):
type S1 interface {
AB() (string, string)
SetAB(a, b string)
}
type s1 struct {
a string `json:"a"`
b string `json:"b"`
}
func (s s1) AB() (string, string) { return s.a, s.b }
func (s *s1) SetAB(a, b string) { s.a, s.b = a, b }
func modifyStruct(s S1) {
a, b := s.AB()
s.SetAB(b, a)
}
Testing it:
s2 := s2{s1: s1{"A", "B"}}
fmt.Println(s2)
modifyStruct(&s2)
fmt.Println(s2)
Output is the same (try it on the Go Playground):
{{A B} }
{{B A} }
Note that (besides the *s1 type itself) any struct type (and also any pointer to struct type) that embeds *s1 automatically (implicitly) implements the S1 interface, and similarly any pointer to struct type that embeds s1 also implements S1 (and therefore *s2 and *s3 in your example).
If you export the fields, then you can use the reflect package to swap the values:
type s1 struct {
A string `json:"a"`
B string `json:"b"`
}
...
func modifyStruct(s interface{}) {
v := reflect.ValueOf(s).Elem()
a := v.FieldByName("A")
b := v.FieldByName("B")
t := reflect.New(a.Type()).Elem()
t.Set(a)
a.Set(b)
b.Set(t)
}
The fields must be exported to use the reflect package because the reflect package cannot set unexported fields.
playground example

Golang godoc - Explain group type declarations

There is a piece of GO code I have seen in the GIN library and in the Google docs that look like the following
type (
T0 []string
T1 []string
T2 struct{ a, b int }
T3 struct{ a, c int }
T4 func(int, float64) *T0
T5 func(x int, y float64) *[]string
)
What I don't understand is, what this grouping is doing and what are some purposes of this implementation (there wasn't much in the docs that went over this topic unless I missed it)
another example from the gin library
type (
RoutesInfo []RouteInfo
RouteInfo struct {
Method string
Path string
Handler string
}
Engine struct {
RouterGroup
HTMLRender render.HTMLRender
allNoRoute HandlersChain
allNoMethod HandlersChain
noRoute HandlersChain
noMethod HandlersChain
pool sync.Pool
trees methodTrees
RedirectTrailingSlash bool
RedirectFixedPath bool
HandleMethodNotAllowed bool
ForwardedByClientIP bool
}
)
And lastly - sorry this is different topic but related to this one
var _ IRouter = &Engine{}
why is there a _ infront of IRouter? I know it's a blank identifier but what purpose does it have in that case
The code
type (
A int
B string
)
is functionality identical to
type A int
type B string
The grouping is just a way to organize code. The grouping is sometimes used to indicate that the types are related in some way.
The use of the blank identifier is explained in Specs: What's the purpose of the blank identifier in variable assignment?.
I think the first part of your question has already been answered. As for the second part, the code
var _ IRouter = &Engine{}
Creates a compile-time check that *Engine implements the IRouter interface. We are assigning a value of type *Engine to a variable that must be of the type IRouter. If a *Engine does not satisfy the interface then it won't compile.
This isn't strictly necessary but some people like to put it in where they define a type to ensure it always satisfies an intended interface.
Regarding 1st question
The statments shown are type declaration
From the Go language spec :
A type declaration binds an identifier, the type name, to a new type that has the same underlying type as an existing type, and operations defined for the existing type are also defined for the new type. The new type is different from the existing type.
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = identifier Type .
In layman terms, you can do :
type
e.g.
type Temperature uint8
type WeekTemp [7]Temperature
For underlying type,
Named instances of the boolean, numeric, and string types are predeclared.
Composite types are constructed using type literals
TypeLiteral = ArrayType | StructType | PointerType | FunctionType |
InterfaceType |
SliceType | MapType | ChannelType .
so you can also equivalently do :
type (
Temperature unit8
WeekTemp [7]Temperature
)
another example for composite type
type Tree struct {
leftChild, rightChild *Tree
}
For 2nd question,
Edited :
I wasn't aware of this but trying on go playground , it looks like the answer from jcbwlkr is indeed right.
So trying to compile
type MyInterface interface{
someMethod()
}
type MyType struct{}
var _ MyInterface = &MyType{}
will give this error
cannot use MyType literal (type *MyType) as type MyInterface in
assignment: *MyType does not implement MyInterface (missing
someMethod method)
So it indeed does a compile time check to make sure that Engine struct conforms to IRouter interface. neat

Return values of function as input arguments to another

If I have
func returnIntAndString() (i int, s string) {...}
And I have:
func doSomething(i int, s string) {...}
Then I can do the following successfully:
doSomething(returnIntAndString())
However, let's say I want to add another argument to doSomething like:
func doSomething(msg string, i int, s string) {...}
Go complains when compiling if I call it like:
doSomething("message", returnIntAndString())
With:
main.go:45: multiple-value returnIntAndString() in single-value context
main.go:45: not enough arguments in call to doSomething()
Is there a way to do this or should I just give up and assign the return values from returnIntAndString to some references and pass msg and these values like doSomething(msg, code, str) ?
It's described here in the spec. It requires the inner function to return the correct types for all arguments. There is no allowance for extra parameters along with a function that returns multiple values.
As a special case, if the return values of a function or method g are
equal in number and individually assignable to the parameters of
another function or method f, then the call f(g(parameters_of_g)) will
invoke f after binding the return values of g to the parameters of f
in order. The call of f must contain no parameters other than the call
of g, and g must have at least one return value. If f has a final ...
parameter, it is assigned the return values of g that remain after
assignment of regular parameters.
func Split(s string, pos int) (string, string) {
return s[0:pos], s[pos:]
}
func Join(s, t string) string {
return s + t
}
if Join(Split(value, len(value)/2)) != value {
log.Panic("test fails")
}
If those specific conditions are not met, then you need to assign the return values and call the function separately.
I had the same question. The best solution I could come up with is creating types or structs for my desired extra parameters and writing methods for them like this:
package main
import (
"fmt"
)
type Message string
type MessageNumber struct {
Message string
Number int
}
func testfunc() (foo int, bar int) {
foo = 4
bar = 2
return
}
func (baz Message) testfunc2(foo int, bar int) {
fmt.Println(foo, bar, baz)
}
func (baz MessageNumber) testfunc3(foo int, bar int) {
fmt.Println(foo, bar, baz.Number, baz.Message)
}
func main() {
Message("the answer").testfunc2(testfunc())
MessageNumber{"what were we talking about again?", 0}.testfunc3(testfunc())
fmt.Println("Done. Have a day.")
}
The output looks like this:
user#Frodos-Atari-MEGA-STE:~/go/test$ go run main.go
4 2 the answer
4 2 0 what were we talking about again?
Done. Have a day.

Resources