Go Generics - Hold a map of generic interfaces [duplicate] - go

This question already has answers here:
Why a generic can't be assigned to another even if their type arguments can?
(1 answer)
Can I construct a slice of a generic type with different type parameters?
(2 answers)
Go generic container with different runtime types
(1 answer)
Closed 11 months ago.
I'm refactoring some of my code now that Go 1.18 is out with the new Generics feature.
I've created a generic interface i.e
type IExample[T any] interface{
ExampleFunc(ex T) T
}
Somewhere in my code, I want to store several implementations of this interface in a map and use them generically in my code.
mapping := map[string]IExample{
// .......
}
But the go compiler throws this error cannot use generic type types.SettingsAdapter[T any] without instantiation
So, I tried adding any to the generic type
mapping := map[string]IExample[any]{
// .......
}
Which resulted in the following error
IExample[any] does not implement IExampleImpl[ExampleT]
At this point, I feel that there's something I'm missing while implementing the code, or that I'm just using this feature in a way that it wasn't meant to be used.
Thanks :)

Related

How do I unwrap a wrapped struct in golang? [duplicate]

This question already has answers here:
struct type embedded fields access
(3 answers)
accessing struct fields from embedded struct
(2 answers)
Nameless fields in Go structs?
(2 answers)
If struct A is embedded in B, can methods on A access method and fields of B?
(2 answers)
Closed 1 year ago.
So I have been searching and can't seem to find how to get the backend struct for a wrapped struct in go.
This is the use case: I am using traffic to manage my web app and it uses it's own wrapped version of the http.Request as well as several others. the declaration looks like this:
type Request struct {
*http.Request
}
I am trying to incorporate go-guardian and I need to send an http.Request to this function:
Authenticate(r *http.Request) (Info, error)
The question is how do I get the *http.Request that the traffic.Request was made out of?
I seem to remember seeing a way to do this in a tutorial somewhere but I haven't been able to find it (the problem is I'm not sure I'm using the right term for a wrapped struct).
Any feedback would be graetly appreciated - thank you.
An embedded field can be accessed using its type name:
type Request struct {
*http.Request
}
For the above:
func f(r *Request) {
// This will pass the embedded *http.Request
g(r.Request)
}

Why use non-struct types in Golang? [duplicate]

I am actually learning golang (from .NET) and there is one thing I don't understand about this language.
Sometimes I find this kind of declaration:
https://github.com/golang/crypto/blob/master/ed25519/ed25519.go
// PublicKey is the type of Ed25519 public keys.
type PublicKey []byte
What does it mean exactly?
Is it a creating a struct which inherit from []byte?
Is it just an alias?
I thought golang forbid inheritance.
It's a type declaration, more specifically a type definition. It creates a new type, having []byte as its underlying type:
A type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it.
New types are created because they can simplify using them multiple times, their identifier (their name) may be expressive in other contexts, and–most importantly–so that you can define (attach) methods to it (you can't attach methods to built-in types, nor to anonymous types or types defined in other packages).
This last part (attaching methods) is important, because even though instead of attaching methods you could just as easily create and use functions that accept the "original" type as parameter, only types with methods can implement interfaces that list ("prescribe") those methods, and as mentioned earlier, you can't attach methods to certain types unless you create a new type derived from them.
As an example, the type []int will never implement the sort.Interface required to be sortable (by the sort package), so a new type sort.IntSlice is created (which is type IntSlice []int) to which the required methods are attached, so you can pass a value of type sort.IntSlice to the sort.Sort() function but not a value of type []int. Since sort.IntSlice has []int as its underlying type, if you have a value of []int, you can simply convert it to sort.IntSlice if you want to sort it, like in this example (try it on the Go Playground):
is := []int{1,3,2}
sort.Sort(sort.IntSlice(is))
fmt.Println(is) // Prints: [1 2 3]
When you create a new type, there is no "inheritance" involved. The new type will have 0 methods. If you want "inheritance-like" functionality, you should check out embedding (in relation with struct types), in which case the embedder type will also "have" the methods of the embedded type.

How to write append "method" in go

I would like to explore Go possibilities. How would you turn "append" to method? simply: "st.app(t) == append(st, t)"
This is what I got:
type T interface{}
type ST []interface{}
func (st []T) app (t T) []T {
return(append(st, t))
}
but this code does not check for type compatibility:
append([]int{1,2},"a") // correctly gives error
ST{1,2}.app("a") // dumbly gives [1 2 a] !!!
I know why the code does not check for type compatibility but What is the right way to do it? Is it possible?
I appreciate your help to understand how Go works.
The right way to do this is to call append() as the built-in function it is. It's not an accident that it's a built-in function; you can't write append itself in Go, and anything that approximates it would be unsafe (and over-complicated).
Don't fight Go. Just write the line of code. In the time you spend trying to create tricky generics, you could have solved three more issues and shipped the product. That's how Go works.
This isn't to say Go will never have generics, but as we move towards Go 2 consider the following from Russ Cox:
For example, I've been examining generics recently, but I don't have in my mind a clear picture of the detailed, concrete problems that Go users need generics to solve. As a result, I can't answer a design question like whether to support generic methods, which is to say methods that are parameterized separately from the receiver. If we had a large set of real-world use cases, we could begin to answer a question like this by examining the significant ones.
(On the other hand, Generics is the most responded-to topic in ExperienceReports, so it's not that no one is aware of the interest. But don't fight Go. It's a fantastic language for shipping great software. It is not, however, a generic language.)
4 years later, there is actually a possible solution to get methods that are parameterized separately from the receiver.
There is with Go 1.18 generics
It does not support parameterized method
It does support parameterized method, meaning the receiver may have type parameters
Jaana B. Dogan proposes "Generics facilitators in Go" based on that
Parameterized receivers are a useful tool and helped me develop a common pattern, facilitators, to overcome the shortcomings of having no parameterized methods.
Facilitators are simply a new type that has access to the type you wished you had generic methods on.
Her example:
package database
type Client struct{ ... }
type Querier[T any] struct {
client *Client
}
func NewQuerier[T any](c *Client) *Querier[T] {
return &Querier[T]{
client: c,
}
}
func (q *Querier[T]) All(ctx context.Context) ([]T, error) {
// implementation
}
func (q *Querier[T]) Filter(ctx context.Context, filter ...Filter) ([]T, error) {
// implementation
You can use it as:
querier := database.NewQuerier[Person](client)
In your case though, while you could define an Appender struct, it still needs to apply on a concrete struct, which is why using the built-in append() remains preferable.
But in general, should you need parameterized methods, Jaana's pattern can help.

How does type aliases work in Go? [duplicate]

This question already has an answer here:
Calling method of named type
(1 answer)
Closed 7 years ago.
I have a type wrapper in my code:
package my_package
import "github.com/gin-gonic/gin"
type Server *gin.Engine
It works perfectly fine to use it within my package like:
func NewServer() Server {
s:= Server(gin.Default())
// I can call *gin.Engine functions on my s here without problems
return s
}
In my test suite (which resides in another package) I import my package and get the Server type. However, when I try to call some "inherited" functions on it doesn't work.
server_test.go:68: server.ServeHTTP undefined (type my_package.Server has no field or method ServeHTTP)
What's going on?
EDIT
The solution I found is related to #jiang-yd answer below:
Change the type to a embedding struct
type Server struct {
*gin.Engine
}
and change the "cast"
s := Server{gin.Default()}
in official document, there are two kinds of type, static type and underlying type. Server is your static type and *gin.Engine is the underlying type. most place in golang just use static type, so Server and *.gin.Engine are two types. check the golang spec
well it not help you in your problem. in your situation, you need embedding struct of golang, which help you inherit all method from one struct to another.

What is the top level interface in go? [duplicate]

This question already has answers here:
What's the meaning of interface{}?
(8 answers)
Closed 7 years ago.
Or what is the interface that all types implement?
I'm looking for something like the Object class in Java.
Is it possible for me to make my own kind of "Root" interface?
Any type that implements all the methods listed in the interface implements the interface.
The empty interface, interface{}, lists no methods. Therefore, all types implement it.
There is nothing "top level" about it however. Interfaces (although they can embed) do not have a hierarchical structure. The empty interface is simply a normal interface with no requirements.

Resources