golang: slice of struct != slice of interface it implements?
I have an interface Model
, which is implemented by struct Person
.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *Person {
var models Person
return &models
}
Go complains with: cannot use newPersons() (type Person) as type Model in return argument
My goal is to return a slice of whatever model type is requested (whether Person
, FutureModel
, Terminator2000
, w/e). What am I missing, and how can I properly implement such a solution?
go
add a comment |
I have an interface Model
, which is implemented by struct Person
.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *Person {
var models Person
return &models
}
Go complains with: cannot use newPersons() (type Person) as type Model in return argument
My goal is to return a slice of whatever model type is requested (whether Person
, FutureModel
, Terminator2000
, w/e). What am I missing, and how can I properly implement such a solution?
go
3
A slice is different from an array in Go. Since you were really talking about slices, I edited your post to reflect this.
– Stephen Weinberg
Oct 21 '12 at 4:15
Stephen, thanks, appreciated :-)
– Jon L.
Oct 21 '12 at 4:23
@JonL. Did you ever figure this out? I'm trying to do the same thing so that I don't have to repeat a ton of code for my/api/{collection}
. I have it working for everything except for an index function that needs to read into a slice.
– Derek Perkins
Jul 25 '14 at 3:44
@DerekPerkins, I don't recall what I ended up doing here, and I haven't played w/ Go in awhile. Sorry I can't be of more assistance.
– Jon L.
Jul 30 '14 at 13:27
Contravariance (or is that covariance?) strikes again!
– David
Jul 19 '18 at 1:08
add a comment |
I have an interface Model
, which is implemented by struct Person
.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *Person {
var models Person
return &models
}
Go complains with: cannot use newPersons() (type Person) as type Model in return argument
My goal is to return a slice of whatever model type is requested (whether Person
, FutureModel
, Terminator2000
, w/e). What am I missing, and how can I properly implement such a solution?
go
I have an interface Model
, which is implemented by struct Person
.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *Person {
var models Person
return &models
}
Go complains with: cannot use newPersons() (type Person) as type Model in return argument
My goal is to return a slice of whatever model type is requested (whether Person
, FutureModel
, Terminator2000
, w/e). What am I missing, and how can I properly implement such a solution?
go
go
edited Apr 12 '17 at 15:14
Flimzy
39.1k106597
39.1k106597
asked Oct 21 '12 at 3:26
Jon L.Jon L.
1,28221329
1,28221329
3
A slice is different from an array in Go. Since you were really talking about slices, I edited your post to reflect this.
– Stephen Weinberg
Oct 21 '12 at 4:15
Stephen, thanks, appreciated :-)
– Jon L.
Oct 21 '12 at 4:23
@JonL. Did you ever figure this out? I'm trying to do the same thing so that I don't have to repeat a ton of code for my/api/{collection}
. I have it working for everything except for an index function that needs to read into a slice.
– Derek Perkins
Jul 25 '14 at 3:44
@DerekPerkins, I don't recall what I ended up doing here, and I haven't played w/ Go in awhile. Sorry I can't be of more assistance.
– Jon L.
Jul 30 '14 at 13:27
Contravariance (or is that covariance?) strikes again!
– David
Jul 19 '18 at 1:08
add a comment |
3
A slice is different from an array in Go. Since you were really talking about slices, I edited your post to reflect this.
– Stephen Weinberg
Oct 21 '12 at 4:15
Stephen, thanks, appreciated :-)
– Jon L.
Oct 21 '12 at 4:23
@JonL. Did you ever figure this out? I'm trying to do the same thing so that I don't have to repeat a ton of code for my/api/{collection}
. I have it working for everything except for an index function that needs to read into a slice.
– Derek Perkins
Jul 25 '14 at 3:44
@DerekPerkins, I don't recall what I ended up doing here, and I haven't played w/ Go in awhile. Sorry I can't be of more assistance.
– Jon L.
Jul 30 '14 at 13:27
Contravariance (or is that covariance?) strikes again!
– David
Jul 19 '18 at 1:08
3
3
A slice is different from an array in Go. Since you were really talking about slices, I edited your post to reflect this.
– Stephen Weinberg
Oct 21 '12 at 4:15
A slice is different from an array in Go. Since you were really talking about slices, I edited your post to reflect this.
– Stephen Weinberg
Oct 21 '12 at 4:15
Stephen, thanks, appreciated :-)
– Jon L.
Oct 21 '12 at 4:23
Stephen, thanks, appreciated :-)
– Jon L.
Oct 21 '12 at 4:23
@JonL. Did you ever figure this out? I'm trying to do the same thing so that I don't have to repeat a ton of code for my
/api/{collection}
. I have it working for everything except for an index function that needs to read into a slice.– Derek Perkins
Jul 25 '14 at 3:44
@JonL. Did you ever figure this out? I'm trying to do the same thing so that I don't have to repeat a ton of code for my
/api/{collection}
. I have it working for everything except for an index function that needs to read into a slice.– Derek Perkins
Jul 25 '14 at 3:44
@DerekPerkins, I don't recall what I ended up doing here, and I haven't played w/ Go in awhile. Sorry I can't be of more assistance.
– Jon L.
Jul 30 '14 at 13:27
@DerekPerkins, I don't recall what I ended up doing here, and I haven't played w/ Go in awhile. Sorry I can't be of more assistance.
– Jon L.
Jul 30 '14 at 13:27
Contravariance (or is that covariance?) strikes again!
– David
Jul 19 '18 at 1:08
Contravariance (or is that covariance?) strikes again!
– David
Jul 19 '18 at 1:08
add a comment |
5 Answers
5
active
oldest
votes
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A Person
and a Model
have different memory layouts. This is because the types they are slices of have different memory layouts. A Model
is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person
is a struct whose size depends on the fields it contains. In order to convert from a Person
to a Model
, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make(Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*Person // pointer to slice
*Person // slice of pointers
Didn't realize at the time, but my answer doesn't directly address the issue raised. This answer addresses it.
– dskinner
Oct 21 '12 at 4:12
Very nice answer, especially with the explanation about the number of words of memory for each type
– I82Much
Oct 21 '12 at 17:16
3
github.com/golang/go/wiki/InterfaceSlice
– Dalibor Filus
Aug 4 '16 at 14:24
Well how do you write something in an abstract, generic way then? Imagine you have 100k results from a database query and you have to iterate over them all and create a copy of each dataset. This means you can't have generic interfaces in Go
– user2312578
Apr 26 '17 at 14:58
Your answer is correct, but the explanation made me think that if I had an interfaceA
which implements my desired interfaceB
I would be able to use a slice ofA
s as a slice ofB
s (after all, the memory structure is identical, since they're both interfaces). I was disappointed to discover I can't :(
– Noam Nelke
yesterday
|
show 1 more comment
Maybe this is an issue with your return type *Person
, where it should actually be *Person
so to reference that each index of the slice is a reference to a Person
, and where a slice is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models *Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
Thanks for the response. While (as you noted) it doesn't directly address the issue at hand, it's an appreciated example nonetheless :-)
– Jon L.
Oct 21 '12 at 4:27
add a comment |
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person
and Politician
both implementing the methods of Model
.
You can still use Person
or Politician
everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model
until you do a manual conversion to
another interface type.
Suppose I have a Person
which implements the method Walk()
and a Model
implements ShowOff()
, the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
You're correct :-( My approach is my attempt to generically provide access to models via a ReST API. So a request to/api/{collection}
would dynamically interact w/ the requested collection. Can you suggest an alternative solution without explicitly testing the requested collection across multiple functions? I guess what I'm looking for is a way to specify a generic return type without losing knowledge of it's type.
– Jon L.
Oct 21 '12 at 4:45
2
Knowledge of the type is always preserved, even if you returninterface{}
, the problem is that you're then need to do runtime type assertions instead of compiler type checking. A generic solution forname -> object
without runtime assertions is only possible using generics, which go does not support. So if you do this, you have to live with reflection or the drawbacks of your solution.
– nemo
Oct 21 '12 at 14:13
point is Model != Person or even Model != Politician. That's the issue.
– user2312578
Apr 26 '17 at 15:05
@dalu Correct. I mention this at the top of my answer as well: this answer gives complementary information regarding typing and go interface conventions that the OP did not seem to know about but the accepted answer did not address.
– nemo
Apr 26 '17 at 17:07
add a comment |
Types T and T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
add a comment |
As others have already answered, T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make(interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf(int{1,2,3})
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f12994679%2fgolang-slice-of-struct-slice-of-interface-it-implements%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A Person
and a Model
have different memory layouts. This is because the types they are slices of have different memory layouts. A Model
is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person
is a struct whose size depends on the fields it contains. In order to convert from a Person
to a Model
, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make(Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*Person // pointer to slice
*Person // slice of pointers
Didn't realize at the time, but my answer doesn't directly address the issue raised. This answer addresses it.
– dskinner
Oct 21 '12 at 4:12
Very nice answer, especially with the explanation about the number of words of memory for each type
– I82Much
Oct 21 '12 at 17:16
3
github.com/golang/go/wiki/InterfaceSlice
– Dalibor Filus
Aug 4 '16 at 14:24
Well how do you write something in an abstract, generic way then? Imagine you have 100k results from a database query and you have to iterate over them all and create a copy of each dataset. This means you can't have generic interfaces in Go
– user2312578
Apr 26 '17 at 14:58
Your answer is correct, but the explanation made me think that if I had an interfaceA
which implements my desired interfaceB
I would be able to use a slice ofA
s as a slice ofB
s (after all, the memory structure is identical, since they're both interfaces). I was disappointed to discover I can't :(
– Noam Nelke
yesterday
|
show 1 more comment
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A Person
and a Model
have different memory layouts. This is because the types they are slices of have different memory layouts. A Model
is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person
is a struct whose size depends on the fields it contains. In order to convert from a Person
to a Model
, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make(Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*Person // pointer to slice
*Person // slice of pointers
Didn't realize at the time, but my answer doesn't directly address the issue raised. This answer addresses it.
– dskinner
Oct 21 '12 at 4:12
Very nice answer, especially with the explanation about the number of words of memory for each type
– I82Much
Oct 21 '12 at 17:16
3
github.com/golang/go/wiki/InterfaceSlice
– Dalibor Filus
Aug 4 '16 at 14:24
Well how do you write something in an abstract, generic way then? Imagine you have 100k results from a database query and you have to iterate over them all and create a copy of each dataset. This means you can't have generic interfaces in Go
– user2312578
Apr 26 '17 at 14:58
Your answer is correct, but the explanation made me think that if I had an interfaceA
which implements my desired interfaceB
I would be able to use a slice ofA
s as a slice ofB
s (after all, the memory structure is identical, since they're both interfaces). I was disappointed to discover I can't :(
– Noam Nelke
yesterday
|
show 1 more comment
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A Person
and a Model
have different memory layouts. This is because the types they are slices of have different memory layouts. A Model
is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person
is a struct whose size depends on the fields it contains. In order to convert from a Person
to a Model
, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make(Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*Person // pointer to slice
*Person // slice of pointers
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A Person
and a Model
have different memory layouts. This is because the types they are slices of have different memory layouts. A Model
is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person
is a struct whose size depends on the fields it contains. In order to convert from a Person
to a Model
, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make(Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*Person // pointer to slice
*Person // slice of pointers
edited May 23 '17 at 12:18
Community♦
11
11
answered Oct 21 '12 at 3:59
Stephen WeinbergStephen Weinberg
34.1k99495
34.1k99495
Didn't realize at the time, but my answer doesn't directly address the issue raised. This answer addresses it.
– dskinner
Oct 21 '12 at 4:12
Very nice answer, especially with the explanation about the number of words of memory for each type
– I82Much
Oct 21 '12 at 17:16
3
github.com/golang/go/wiki/InterfaceSlice
– Dalibor Filus
Aug 4 '16 at 14:24
Well how do you write something in an abstract, generic way then? Imagine you have 100k results from a database query and you have to iterate over them all and create a copy of each dataset. This means you can't have generic interfaces in Go
– user2312578
Apr 26 '17 at 14:58
Your answer is correct, but the explanation made me think that if I had an interfaceA
which implements my desired interfaceB
I would be able to use a slice ofA
s as a slice ofB
s (after all, the memory structure is identical, since they're both interfaces). I was disappointed to discover I can't :(
– Noam Nelke
yesterday
|
show 1 more comment
Didn't realize at the time, but my answer doesn't directly address the issue raised. This answer addresses it.
– dskinner
Oct 21 '12 at 4:12
Very nice answer, especially with the explanation about the number of words of memory for each type
– I82Much
Oct 21 '12 at 17:16
3
github.com/golang/go/wiki/InterfaceSlice
– Dalibor Filus
Aug 4 '16 at 14:24
Well how do you write something in an abstract, generic way then? Imagine you have 100k results from a database query and you have to iterate over them all and create a copy of each dataset. This means you can't have generic interfaces in Go
– user2312578
Apr 26 '17 at 14:58
Your answer is correct, but the explanation made me think that if I had an interfaceA
which implements my desired interfaceB
I would be able to use a slice ofA
s as a slice ofB
s (after all, the memory structure is identical, since they're both interfaces). I was disappointed to discover I can't :(
– Noam Nelke
yesterday
Didn't realize at the time, but my answer doesn't directly address the issue raised. This answer addresses it.
– dskinner
Oct 21 '12 at 4:12
Didn't realize at the time, but my answer doesn't directly address the issue raised. This answer addresses it.
– dskinner
Oct 21 '12 at 4:12
Very nice answer, especially with the explanation about the number of words of memory for each type
– I82Much
Oct 21 '12 at 17:16
Very nice answer, especially with the explanation about the number of words of memory for each type
– I82Much
Oct 21 '12 at 17:16
3
3
github.com/golang/go/wiki/InterfaceSlice
– Dalibor Filus
Aug 4 '16 at 14:24
github.com/golang/go/wiki/InterfaceSlice
– Dalibor Filus
Aug 4 '16 at 14:24
Well how do you write something in an abstract, generic way then? Imagine you have 100k results from a database query and you have to iterate over them all and create a copy of each dataset. This means you can't have generic interfaces in Go
– user2312578
Apr 26 '17 at 14:58
Well how do you write something in an abstract, generic way then? Imagine you have 100k results from a database query and you have to iterate over them all and create a copy of each dataset. This means you can't have generic interfaces in Go
– user2312578
Apr 26 '17 at 14:58
Your answer is correct, but the explanation made me think that if I had an interface
A
which implements my desired interface B
I would be able to use a slice of A
s as a slice of B
s (after all, the memory structure is identical, since they're both interfaces). I was disappointed to discover I can't :(– Noam Nelke
yesterday
Your answer is correct, but the explanation made me think that if I had an interface
A
which implements my desired interface B
I would be able to use a slice of A
s as a slice of B
s (after all, the memory structure is identical, since they're both interfaces). I was disappointed to discover I can't :(– Noam Nelke
yesterday
|
show 1 more comment
Maybe this is an issue with your return type *Person
, where it should actually be *Person
so to reference that each index of the slice is a reference to a Person
, and where a slice is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models *Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
Thanks for the response. While (as you noted) it doesn't directly address the issue at hand, it's an appreciated example nonetheless :-)
– Jon L.
Oct 21 '12 at 4:27
add a comment |
Maybe this is an issue with your return type *Person
, where it should actually be *Person
so to reference that each index of the slice is a reference to a Person
, and where a slice is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models *Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
Thanks for the response. While (as you noted) it doesn't directly address the issue at hand, it's an appreciated example nonetheless :-)
– Jon L.
Oct 21 '12 at 4:27
add a comment |
Maybe this is an issue with your return type *Person
, where it should actually be *Person
so to reference that each index of the slice is a reference to a Person
, and where a slice is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models *Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
Maybe this is an issue with your return type *Person
, where it should actually be *Person
so to reference that each index of the slice is a reference to a Person
, and where a slice is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models *Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
answered Oct 21 '12 at 4:05
dskinnerdskinner
6,86012541
6,86012541
Thanks for the response. While (as you noted) it doesn't directly address the issue at hand, it's an appreciated example nonetheless :-)
– Jon L.
Oct 21 '12 at 4:27
add a comment |
Thanks for the response. While (as you noted) it doesn't directly address the issue at hand, it's an appreciated example nonetheless :-)
– Jon L.
Oct 21 '12 at 4:27
Thanks for the response. While (as you noted) it doesn't directly address the issue at hand, it's an appreciated example nonetheless :-)
– Jon L.
Oct 21 '12 at 4:27
Thanks for the response. While (as you noted) it doesn't directly address the issue at hand, it's an appreciated example nonetheless :-)
– Jon L.
Oct 21 '12 at 4:27
add a comment |
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person
and Politician
both implementing the methods of Model
.
You can still use Person
or Politician
everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model
until you do a manual conversion to
another interface type.
Suppose I have a Person
which implements the method Walk()
and a Model
implements ShowOff()
, the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
You're correct :-( My approach is my attempt to generically provide access to models via a ReST API. So a request to/api/{collection}
would dynamically interact w/ the requested collection. Can you suggest an alternative solution without explicitly testing the requested collection across multiple functions? I guess what I'm looking for is a way to specify a generic return type without losing knowledge of it's type.
– Jon L.
Oct 21 '12 at 4:45
2
Knowledge of the type is always preserved, even if you returninterface{}
, the problem is that you're then need to do runtime type assertions instead of compiler type checking. A generic solution forname -> object
without runtime assertions is only possible using generics, which go does not support. So if you do this, you have to live with reflection or the drawbacks of your solution.
– nemo
Oct 21 '12 at 14:13
point is Model != Person or even Model != Politician. That's the issue.
– user2312578
Apr 26 '17 at 15:05
@dalu Correct. I mention this at the top of my answer as well: this answer gives complementary information regarding typing and go interface conventions that the OP did not seem to know about but the accepted answer did not address.
– nemo
Apr 26 '17 at 17:07
add a comment |
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person
and Politician
both implementing the methods of Model
.
You can still use Person
or Politician
everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model
until you do a manual conversion to
another interface type.
Suppose I have a Person
which implements the method Walk()
and a Model
implements ShowOff()
, the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
You're correct :-( My approach is my attempt to generically provide access to models via a ReST API. So a request to/api/{collection}
would dynamically interact w/ the requested collection. Can you suggest an alternative solution without explicitly testing the requested collection across multiple functions? I guess what I'm looking for is a way to specify a generic return type without losing knowledge of it's type.
– Jon L.
Oct 21 '12 at 4:45
2
Knowledge of the type is always preserved, even if you returninterface{}
, the problem is that you're then need to do runtime type assertions instead of compiler type checking. A generic solution forname -> object
without runtime assertions is only possible using generics, which go does not support. So if you do this, you have to live with reflection or the drawbacks of your solution.
– nemo
Oct 21 '12 at 14:13
point is Model != Person or even Model != Politician. That's the issue.
– user2312578
Apr 26 '17 at 15:05
@dalu Correct. I mention this at the top of my answer as well: this answer gives complementary information regarding typing and go interface conventions that the OP did not seem to know about but the accepted answer did not address.
– nemo
Apr 26 '17 at 17:07
add a comment |
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person
and Politician
both implementing the methods of Model
.
You can still use Person
or Politician
everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model
until you do a manual conversion to
another interface type.
Suppose I have a Person
which implements the method Walk()
and a Model
implements ShowOff()
, the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person
and Politician
both implementing the methods of Model
.
You can still use Person
or Politician
everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model
until you do a manual conversion to
another interface type.
Suppose I have a Person
which implements the method Walk()
and a Model
implements ShowOff()
, the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
answered Oct 21 '12 at 4:12
nemonemo
36.2k789101
36.2k789101
You're correct :-( My approach is my attempt to generically provide access to models via a ReST API. So a request to/api/{collection}
would dynamically interact w/ the requested collection. Can you suggest an alternative solution without explicitly testing the requested collection across multiple functions? I guess what I'm looking for is a way to specify a generic return type without losing knowledge of it's type.
– Jon L.
Oct 21 '12 at 4:45
2
Knowledge of the type is always preserved, even if you returninterface{}
, the problem is that you're then need to do runtime type assertions instead of compiler type checking. A generic solution forname -> object
without runtime assertions is only possible using generics, which go does not support. So if you do this, you have to live with reflection or the drawbacks of your solution.
– nemo
Oct 21 '12 at 14:13
point is Model != Person or even Model != Politician. That's the issue.
– user2312578
Apr 26 '17 at 15:05
@dalu Correct. I mention this at the top of my answer as well: this answer gives complementary information regarding typing and go interface conventions that the OP did not seem to know about but the accepted answer did not address.
– nemo
Apr 26 '17 at 17:07
add a comment |
You're correct :-( My approach is my attempt to generically provide access to models via a ReST API. So a request to/api/{collection}
would dynamically interact w/ the requested collection. Can you suggest an alternative solution without explicitly testing the requested collection across multiple functions? I guess what I'm looking for is a way to specify a generic return type without losing knowledge of it's type.
– Jon L.
Oct 21 '12 at 4:45
2
Knowledge of the type is always preserved, even if you returninterface{}
, the problem is that you're then need to do runtime type assertions instead of compiler type checking. A generic solution forname -> object
without runtime assertions is only possible using generics, which go does not support. So if you do this, you have to live with reflection or the drawbacks of your solution.
– nemo
Oct 21 '12 at 14:13
point is Model != Person or even Model != Politician. That's the issue.
– user2312578
Apr 26 '17 at 15:05
@dalu Correct. I mention this at the top of my answer as well: this answer gives complementary information regarding typing and go interface conventions that the OP did not seem to know about but the accepted answer did not address.
– nemo
Apr 26 '17 at 17:07
You're correct :-( My approach is my attempt to generically provide access to models via a ReST API. So a request to
/api/{collection}
would dynamically interact w/ the requested collection. Can you suggest an alternative solution without explicitly testing the requested collection across multiple functions? I guess what I'm looking for is a way to specify a generic return type without losing knowledge of it's type.– Jon L.
Oct 21 '12 at 4:45
You're correct :-( My approach is my attempt to generically provide access to models via a ReST API. So a request to
/api/{collection}
would dynamically interact w/ the requested collection. Can you suggest an alternative solution without explicitly testing the requested collection across multiple functions? I guess what I'm looking for is a way to specify a generic return type without losing knowledge of it's type.– Jon L.
Oct 21 '12 at 4:45
2
2
Knowledge of the type is always preserved, even if you return
interface{}
, the problem is that you're then need to do runtime type assertions instead of compiler type checking. A generic solution for name -> object
without runtime assertions is only possible using generics, which go does not support. So if you do this, you have to live with reflection or the drawbacks of your solution.– nemo
Oct 21 '12 at 14:13
Knowledge of the type is always preserved, even if you return
interface{}
, the problem is that you're then need to do runtime type assertions instead of compiler type checking. A generic solution for name -> object
without runtime assertions is only possible using generics, which go does not support. So if you do this, you have to live with reflection or the drawbacks of your solution.– nemo
Oct 21 '12 at 14:13
point is Model != Person or even Model != Politician. That's the issue.
– user2312578
Apr 26 '17 at 15:05
point is Model != Person or even Model != Politician. That's the issue.
– user2312578
Apr 26 '17 at 15:05
@dalu Correct. I mention this at the top of my answer as well: this answer gives complementary information regarding typing and go interface conventions that the OP did not seem to know about but the accepted answer did not address.
– nemo
Apr 26 '17 at 17:07
@dalu Correct. I mention this at the top of my answer as well: this answer gives complementary information regarding typing and go interface conventions that the OP did not seem to know about but the accepted answer did not address.
– nemo
Apr 26 '17 at 17:07
add a comment |
Types T and T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
add a comment |
Types T and T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
add a comment |
Types T and T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Types T and T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
answered Oct 21 '12 at 3:58
zzzzzzzz
54.5k12131114
54.5k12131114
add a comment |
add a comment |
As others have already answered, T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make(interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf(int{1,2,3})
add a comment |
As others have already answered, T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make(interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf(int{1,2,3})
add a comment |
As others have already answered, T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make(interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf(int{1,2,3})
As others have already answered, T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make(interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf(int{1,2,3})
answered Jan 28 '15 at 5:00
slavikmslavikm
483
483
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f12994679%2fgolang-slice-of-struct-slice-of-interface-it-implements%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
A slice is different from an array in Go. Since you were really talking about slices, I edited your post to reflect this.
– Stephen Weinberg
Oct 21 '12 at 4:15
Stephen, thanks, appreciated :-)
– Jon L.
Oct 21 '12 at 4:23
@JonL. Did you ever figure this out? I'm trying to do the same thing so that I don't have to repeat a ton of code for my
/api/{collection}
. I have it working for everything except for an index function that needs to read into a slice.– Derek Perkins
Jul 25 '14 at 3:44
@DerekPerkins, I don't recall what I ended up doing here, and I haven't played w/ Go in awhile. Sorry I can't be of more assistance.
– Jon L.
Jul 30 '14 at 13:27
Contravariance (or is that covariance?) strikes again!
– David
Jul 19 '18 at 1:08