Why the init of interface could make an error - go

I mean the interface could even contain a composite type like struct
type A struct {
}
func main() {
var a interface{} = A{}
}
Its weird that interface cant initialize by the brace below this.
type C interface {
}
func main() {
_ = C{}
}
Compile result here:invalid composite literal type C

C is an interface type and therefore cannot be initialized with a composite literal.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated.
https://golang.org/ref/spec#Composite_literals
To make the code compile you could do this:
type C interface {
}
func main() {
_ = C(nil)
}

Related

Instantiate generic interface with any, struct doesn't implement it

Can someone explain, why *DataTo does not satisfy ToType[any]?
Trying to build a DTOer, that copies all values of one struct to another and also sets some explicit values (V in this case)
https://go.dev/play/p/-oobZrw5Ewe
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type DataFrom struct {
V1 int
}
type DataTo struct {
V int
}
func (m *DataTo) SetVal() {
m.V = 1
return
}
type ToType[T any] interface {
SetVal()
*T
}
type DTO[TFrom any, TTo ToType[any]] struct {
Get func(from TFrom) TTo
}
func main() {
dto := &DTO[DataFrom, *DataTo]{
Get: func(from DataFrom) *DataTo {
return &DataTo{V: from.V1 + 666}
},
}
vFrom := DataFrom{V1: 1}
vTo := dto.Get(vFrom)
fmt.Println(vTo.V)
}
Because any is a static type.
If you use it to instantiate a generic type like ToType, that generic type will expect exactly any.
Now, certain usages of the type parameter might hide this issue, for example:
type Foo[T any] struct {
Value T
}
Foo[any]{Value: 12} // ok
Normally you are able to assign whatever type to any like the above, because any is just an alias of the empty interface interface{}, and any type satisfies the empty interface.
When the type parameter is used in composite types such as *T, then instantiating with any means exactly *any. Therefore you can imagine ToType[any] as the same thing as:
type ToTypeAny interface {
SetVal()
*any
}
And then *DataTo is obviously not *any. Further details: Assign struct pointer to interface pointer
If you declare the struct as follows it will compile:
type DTO[TFrom any, TTo ToType[DataTo]] struct {
Get func(from TFrom) TTo
}
Or in a more "generic" but also more verbose way:
type DTO[TFrom any, T any, TTo ToType[T]] struct {
Get func(from TFrom) TTo
}
&DTO[DataFrom, DataTo, *DataTo]{ ... }

How to implement two interfaces with same method name and different arguments

I have two different interfaces (from two different packages) that I want to implement. But they conflict, like this:
type InterfaceA interface {
Init()
}
type InterfaceB interface {
Init(name string)
}
type Implementer struct {} // Wants to implement A and B
func (i Implementer) Init() {}
func (i Implementer) Init(name string) {} // Compiler complains
It says "Method redeclared". How can one struct implement both interfaces?
As already answered, this is not possible since Golang does not (and probably will not) support method overloading.
Look at Golang FAQ:
Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.
It is not possible.
In go you must have a single method signature.
You should rename one method.
The method signatures must match. If you want dependency injection I would recommend the functional option pattern. Functional options are functions that return other functions that are called in a loop in the constructor. Here is an example of how to use functional options and the basics of interfaces in go.
package main
import (
"fmt"
"strconv"
)
type SomeData struct {
data string
}
// SomeData and SomeOtherData both implement SomeInterface and SomeOtherInterface
// SomeInterface and SomeOtherInterface both implement each other.
type SomeInterface interface {
String() string
Set(data string)
}
func (s *SomeData)String() string {
return s.data
}
func (s *SomeData)Set(data string) {
s.data = data
}
// SetDataOption is a functional option that can be used to inject a constructor dep
func SetDataOption(data string) func(*SomeData) {
return func(s *SomeData) {
s.Set(data)
}
}
// NewSomeData is the constructor; it takes in 0 to many functional options and calls each one in a loop.
func NewSomeData(options ...func(s *SomeData)) SomeInterface {
s := new(SomeData)
for _, o := range options {
o(s)
}
return s
}
//********************
type SomeOtherData struct {
data string
i int
}
type SomeOtherInterface interface {
String() string
Set(data string)
}
func (s *SomeOtherData)String() string {
return s.data + " " + strconv.Itoa(s.i)
}
func (s *SomeOtherData)Set(data string) {
s.data = data
}
func SetOtherDataOption(data string) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.Set(data)
}
}
func SetOtherIntOption(i int) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.i = i
}
}
// NewSomeOther data works just like NewSomeData only in this case, there are more options to choose from
// you can use none or any of them.
func NewSomeOtherData(options ...func(s *SomeOtherData)) SomeOtherInterface {
s := new(SomeOtherData)
for _, o := range options {
o(s)
}
return s
}
//*********************************
// HandleData accepts an interface
// Regardless of which underlying struct is in the interface, this function will handle
// either by calling the methods on the underlying struct.
func HandleData(si SomeInterface) {
fmt.Println(si) // fmt.Println calls the String() method of your struct if it has one using the Stringer interface
}
func main() {
someData := NewSomeData(SetDataOption("Optional constructor dep"))
someOtherData := NewSomeOtherData(SetOtherDataOption("Other optional constructor dep"), SetOtherIntOption(42))
HandleData(someData) // calls SomeData.String()
HandleData(someOtherData) // calls SomeOtherData.String()
someOtherData = someData // assign the first interface to the second, this works because they both implement each other.
HandleData(someOtherData) // calls SomeData.String() because there is a SomeData in the someOtherData variable.
}

Go - storing structs with the same embedded struct in a list

I have multiple structs with the same embedded struct. In one of the structs I would like to store a list of any struct that embeds the base struct. Here is a small snippet showing the case.
package main
type Symbol interface{}
type Base struct {
a int32
}
type Foo struct {
Base
b int32
Symbols []Base
// Below works
// Symbols []Symbol
}
type Bar struct {
Base
c int32
}
func main () {
var bar Bar
var foo Foo
foo.Symbols = append(foo.Symbols, bar)
}
However, this does not work. I get ./main.go:25:22: cannot use bar (type Bar) as type Base in append. When I use the empty Symbol interface, everything works. However this approach completely bypasses the type system as now everything can be stored in the list. I would like to somehow denote that only Base, Foo and Bar can be stored in the list, so that compiler can check if this rquirement is met. My structs do not have any methods, for sure not the ones that share behavior and can be added to the interface. Adding some dummy method to the interface and dummy implementations seems very artificial. What is the Go idiomatic way of handling such scenarios?
What matters is the same interface:
package main
import (
"fmt"
)
type Item interface{
fmt.Stringer
}
type ItemA struct {
}
func (a ItemA) String() string {
return "item A"
}
type ItemB struct {
}
func (a ItemB) String() string {
return "item B"
}
func main() {
items := make([]Item, 0)
items = append(items, ItemA{}, ItemB{})
fmt.Printf("Items: %v", items)
}
What you seem to be expecting is subtype polymorphism. Go does not support dynamic binding for non-interface types. Therefore you you could either use interfaces
package main
func main(){
var bar Bar
var foo Foo
foo.Symbols = append(foo.Symbols, bar)
}
type Symbol interface {
Symbol()
}
type Base struct {
a int32
}
func (b Base)Symbol(){}
type Foo struct {
Base
b int32
Symbols []Symbol
}
type Bar struct {
Base
c int32
}
or if you dislike using interfaces, you can use a trick like below with reflect.
package main
import "fmt"
func main(){
var bar Bar
var foo Foo
err := foo.AddSymbol(bar)
if err != nil{
fmt.Println(err)
}
}
type Base struct {
a int32
}
func (b Base)Symbol(){}
type Foo struct {
Base
b int32
symbol []interface{} // field made private
}
// AddSymbol : helper to append values
func (f *Foo)AddSymbol(in interface{})(err error){
if f.symbol == nil{
f.symbol = make([]interface{},0)
}
switch typ := in.(type) {
case Base,Bar,Foo:
f.symbol = append(f.symbol,in)
default:
return fmt.Errorf("provided type: %s is not supported",typ)
}
return nil
}
type Bar struct {
Base
c int32
}
I did some searching and reading. What I want to achieve requires so called "sum types". Currently Go does not support sum types. However, there are few alternative to simulate the behavior of sum types. They are quite nicely described here Alternatives to sum types in Go.
What is more, it looks like sum types will probably be supported in the Go 2. Further reading proposal: spec: add sum types / discriminated unions, spec: generics: use type sets to remove type keyword in constraints.

Assign struct pointer to interface pointer

I'm trying to refactor some golang source code, and I would like to use interfaces but I find huge difficulties (bear with me, I'm a hard-core C/C++ orphan)
I extracted a small sample exhibiting the error I get
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return m.a
}
func main() {
t := &(MyProcessor{2})
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
fmt.Println((*t).Init(), (*p).Init())
}
Why is the second assignment failing?
Adding the code modified to demonstrate what I was trying to do. I thought interfaces where more similar to C++ classes. My fault. Still learning
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m *MyProcessor) Init() int {
m.a++
return m.a
}
func main() {
t := &(MyProcessor{2})
m := MyProcessor{4}
var p LogProcessor = &m
fmt.Println(t.Init(), p.Init())
fmt.Println(t.a, m.a)
}
The expression MyProcessor{2} is a composite literal. It is valid to take the address of a composite literal, and it will be of type *MyProcessor.
So here:
t := &(MyProcessor{2})
Type of t will be *MyProcessor.
Your failing line:
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
The type of the expression on the right hand side is again *MyProcessor. It's a pointer to a concrete type. The type of p is *LogProcessor, it's a pointer to another type. Assignability rules don't apply here, so the value is simply not assignable to the variable p.
Note that there is an assignability rule:
A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
...
T is an interface type and x implements T.
In your example p's type is not an interface type, but a pointer to interface. You rarely (if ever) need this in go.
Instead if you use "just" the interface type:
var p LogProcessor = &(MyProcessor{4}) // This works!
This works because the concrete type *MyProcessor implements the interface type LogProcessor. You also don't need the parenthesis, you may simply use &MyProcessor{4}.
Then of course you can't dereference p (as it's not a pointer), so you have to use p.Init().
it is failing because you are using a pointer to an interface, if you remove the pointer to LogProcessor for var p it works
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return 2
}
func main() {
t := &(MyProcessor{2})
var p LogProcessor = MyProcessor{4} // works without a pointer to the interface type
fmt.Println((*t).Init(), (p).Init())
}

Can't pass slices of structs implementing the Foo interface to a function that expects []Foo

I'm trying to work with interfaces in Go but I can't seem to be able to pass a slice of structs implementing a certain interface to a function that expects a slice of the interface. It works with functions that just takes a single object but not with functions expecting slices of the interface. Using the code below I get the following error:
./main.go:27: cannot use fooBar (type []*FooBar) as type []Foo in argument to FooBarBar
Here is the code:
package main
import "fmt"
type Foo interface {
Bar() bool
}
type FooBar struct {
a bool
}
func (f *FooBar) Bar() bool {
return f.a
}
func FooBarBar(foos []Foo) {
for _, foo := range foos {
fmt.Println(foo.Bar())
}
}
func main() {
fooBar := make([]*FooBar, 2)
fooBar[0] = &FooBar{true}
fooBar[1] = &FooBar{false}
FooBarBar(fooBar)
}
There is no "sub typing" in Go.
[]Foo and []*Foobar are 2 different types, so all you can do is use a for loop to convert []*Foobar into []Foo
foos := []Foo{}
for _,f:=range foobar {
foos = append(foos,f)
}
FooBarBar(foos)
Or you can put your *Foobar directly in a slice of Foo :
foos := []Foo{&FooBar{true},&FooBar{false}}
FooBarBar(foos)
There are a few exceptions like the relationship between named types and unnamed types
type FooBar struct{}
type Foobars []*FooBar // Foobars is an named type, []*FooBar is an unnamed type
AcceptFoobars := func(f []*FooBar) {} // Accepts Foobars too
foobars := Foobars{{}, {}, {}}
AcceptFoobars(foobars)
Go type system is "flat", there is no inheritance or casting, only assertions and conversions. as defined by the Go spec.
https://golang.org/ref/spec#Types
A type determines the set of values and operations specific to values
of that type. Types may be named or unnamed. Named types are specified
by a (possibly qualified) type name; unnamed types are specified using
a type literal, which composes a new type from existing types.
Can i try this way:
func main() {
fooBar := []Foo{&FooBar{true}, &FooBar{false}}
FooBarBar(fooBar)
}
GoPlayGround:

Resources