This question already has an answer here:
cannot infer V: infer type parameter from constraint implementation
(1 answer)
Closed 5 months ago.
Say I have the following code:
type Getter[T any] interface {
Get() T
}
type Wrapper[T any] struct {
a T
}
func (s Wrapper[T]) Get() T {
return s.a
}
Here, you can say that Wrapper[T] implements Getter[T] - since it implements Get() T which is the only requirement.
Now, I have a function that needs to take a Getter[T] in order to return the internal value...
func Return[T any](i Getter[T]) T {
return i.Get()
}
var s1 = Wrapper[int]{
a: 5,
}
Here, Return just gets the value inside - so the expectation is that when I pass in s1, I should get 5 in return.
var s2 = Return(s1) // type Wrapper[int] of s1 does not match Getter[T] (cannot infer T)
...instead, I get that error. Now, there is an easy workaround here...
func (s Wrapper[T]) Getter() Getter[T] {
return s
}
var s2 = Return(s1.Getter())
This ends up working. Getter() does nothing but return itself - functionally speaking, s1 and s1.Getter() should be identical here - and yet it doesn't work. T can be inferred in the method, but not as a parameter.
My question is this: Am I doing something wrong here - or is this just a part of Go? For this example to work, do I need to add a dummy method just to help the compiler - or am I missing something?
You do not need to add methods to Wrapper, but if type inference does not succeed (the compiler can't infer all types), you have to provide the types for the type parameters explicitly, like this:
var s2 = Return[int](s1)
The Return() function has a type parameter, if you provide the type for T explicitly (int here), then the compiler will be able to validate that s1 does indeed implement the Getter[int] interface. Try it on the Go Playground.
This question already has answers here:
Understanding polymorphism in Go
(2 answers)
Embedded types and polymorphism with structs
(2 answers)
Polymorphism in Go - does it exist?
(4 answers)
Multiple Struct switch?
(2 answers)
Closed 10 months ago.
I wish to use multiple structs which inherits from the same Base struct in a polymorphic manner.
Given those structs:
type Base struct { X bool }
type A struct {
Base // inherit Base
A bool
}
type B struct {
Base // inherit Base
B bool
}
I would like to pass either of those structs as an argument to a function polymorphically, and maybe read (or update) one of the Base struct fields:
func CheckIfX(base *Base) bool { // supposed to be a polymorphic function..
return base.X
}
b := &B{
Base{
X: true,
},
B: true,
}
CheckIfX(b) // fail with error..
What I have tried up until now:
Using interface{} and dynamic parsing within the function
(link to playground)
Make structs inherit from an interface
(link to playground).
Drawbacks:
No actual need of implementing methods on my use case, so feels like an overkill
Structs wont parse as expected (for example when trying to save on Firestore..)
I would also like to ask:
Lets say we couldn't come up with something better than dynamic parsing,
would you consider it a better practice than simply use 2 (or more) separet functions (rather than forcing it on a single one)?
I've been daydreaming about this language where you can define different functions with the same name but whose arguments are of different type (or length).
Here's a naive example, assuming a C-like syntax.
struct vect {
int x;
int y;
};
struct guy {
struct vect pos;
char *name;
};
struct guy new_guy(vect v, char *name) {
struct guy g;
g.pos = v;
g.name = name;
return g;
}
struct guy new_guy(int x, int y, char *name) {
struct vect v;
v.x = x;
v.y = y;
return new_guy(v, name);
}
int get_x(struct vect v) {
return v.x;
}
int get_x(struct guy g) {
return g.pos.x;
}
The point would be in avoiding having long names like: get_vect_x and get_guy_x, etc. The compiler knows what types we are using to call a function so it shouldn't be a problem to figure out which definition to use.
There could also be different definitions for different number of arguments.
From Wiki:
In some programming languages, function overloading or method overloading is the ability to create multiple functions of the same name with
different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call,
allowing one function call to perform different tasks depending on context.
wiki link giving definition of function overloading
Java is capable of this, which would lead me to wonder if C++ is (much less experienced with it than Java). Declaring methods of the same name with different parameters or similar parameters different types is supported, even with constructors. This is likely easily implemented in Java because it's a statically typed language. A quick way to check if this is possible is to look at the docs of a particular language's standard libraries for constructors that take different combinations of parameters.
This question already has answers here:
json.Marshal(struct) returns "{}"
(3 answers)
Closed 6 years ago.
I want to Marshal and Unmarshal a recursive type in go something like this:
type Dog struct {
age int
sibling *Dog
}
Is there any way to do this in golang? I tried with json.Marshal but it doesn't work.
Your problem is not with recursion, it's understand encapsulation with Golang, e.i. public and private members.
In order to encode in Go, your struct has to have public fields (starting with Uppercase):
type Dog struct {
Age int
Sibling *Dog
}
Full example: https://play.golang.org/p/eNdLaTfKtN
I am coming from C# background, and I am little confused with the way of GoLang initialization and zeroing definitions. I think you can guess that this confusion arises from make() and new() functions in Go. What should I expect happening internally when these methods run? What happens when initialization and zeroing happens?
I know that there is an init() function in GoLang that is used to initialize packages. But I think it is different than this.
Anyways, what is the difference between them?
Update
I answered my own question, please check it to see my answer.
I think I have figured it and decided to share what I figured so far.
make() vs. new()
I think I now understand the difference between make() and new(). At first, it was little confusing, but here what I got:
new is simply like new in C# or Java, but since there is no constructor in Go, all the fields (like in Java and C# terminology) will be zeroed. Zeroing means more like defaulting the fields. So if the field type is int, then it will be 0, or if it is a struct, then it will be defaulted to nil, and "" for string types. It is actually similar to C# and Java when there is only parameterless constructor available and you are not setting the members to something else manually.
However, types like map, slice, and channels are different. They are different because they are actually wrapper types that wrap an array type to hold the values behind the scenes. So something like List<T> or ArrayList in C# and Java. But using new is not enough in this situation, because the underlying array should be initialized to an empty array to be usable. Because you cannot add or remove from a field of type array which is nil (or null). Therefore, they provided a make() method to help you to initialize slices and such.
So what happens when you use new() over slices, for instance? Simple: Since the underlying array will be nil, the slice will be pointing at a nil array.
So new() would look like the following C#/Java code:
public class Person{
public string Name;
public int Age;
public Address HomeAddress;
}
var person = new Person();
Console.WriteLine(person.Name); // ""
Console.WriteLine(person.Age); // 0
Console.WriteLine(person.HomeAddress); // null
make(), on the other hand, would look like this for slice,map, and channels:
public class PersonList{
// We are initializing the array so that we can use it.
// Its capacity can increase.
private Person[] _personList = new Person[100];
public void Add(Person p){}
public void Remove(Person p){}
public Person Get(int index){}
}
Initialization vs. Zeroing
Simply speaking, zeroing is a form of initialization. At first, I thought they were different but they are not. Initialization is a more general term, whereas if you are set the fields (properties, etc.) of a struct or a variable to its type default such as 0, nil, "", false, etc., then this is called zeroing. However, you can, for instance, use Composite Literals like hello := Hello{name="world"}, which is similar to var hello = new Hello() {Name = "World"} in C#, then you initialize your Hello object with a name field set to world.
In C#, at the time you say new List<string>(), [the underlying array field is initialized to a new array], and make) is performing a similar operation behind the scenes but as a language construct (built in the language itself):
(http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646):
So new does zeroing and returns a pointer back. Whereas make() initializes to underlying array to an array with default values for each element and returns the value itself rather than a pointer.
new returns a pointer to the type, and it's the only way to return a pointer to a native type in one step (aka int, float, complex):
intPtr := new(int)
// or
var i int
intPtr := &i
make is for initializing channels, slices and maps.
All variables are zeroed on creation, regardless of how you create them.
The spec about make: https://golang.org/ref/spec#Making_slices_maps_and_channels
The spec about zero value: https://golang.org/ref/spec#The_zero_value
new(T) allocates zeroed storage for a new item of type T and returns its address, a value of type *T: it returns a pointer to a newly allocated zero value of type T, ready for use; it applies to value types like arrays and structs. It is
equivalent to &T{ }
make(T) returns an initialized value of type T; it applies only to the 3 built-in
reference types: slices, maps, and channels.
var p *[]int = new([]int) // *p == nil; with len and cap 0
//or
p := new([]int)
var v []int = make([]int, 10, 50)
//or
v := make([]int, 10, 50)
//This allocates an array of 50 ints and then creates a slice v with length 10 and capacity 50 pointing
//to the first 10 elements of the array