Reputation: 4119
Assuming I got a type named State
:
type State struct {
// ... does not matter what is inside
}
along with a method defined on it:
func (s *State) prettyName() string {
return "I am a state!"
}
Currently there is no way I can alter prettyName()
's behavior. I known that Go
intentionally escapes OOP-like inheritance and methods overloading and this would probably never change, but still: what if I need prettyName()
to behave differently depending upon whatever factor? The only solution I see is:
type State struct {
_prettyName func() string
}
func (s *State) prettyName() string {
return s._prettyName()
}
Is there a better Go
-style way to achieve the same goal?
Upvotes: 0
Views: 2291
Reputation: 20880
Instead of having prettyName
as method on the struct
, you can also define a member value of function type.
type State struct {
prettyName func() string
}
Then you can set its value to any function at runtime
a := State{}
a.prettyName = func() string {
return "I am a state!"
}
fmt.Println(a.prettyName())
a.prettyName = func() string {
return "another state"
}
fmt.Println(a.prettyName())
This example is on playground
Now you can define an interface type with PrettyName
API and further algorithms/business logic will call PrettyName
.
type StateAPI interface {
PrettyName () string
}
To fit your State
type into the StateAPI
interface, you need to define a trivial PrettyName
method around the private function member
func (s *State) PrettyName() string {
return s.prettyName()
}
This is basically your original idea and it is totally legitimate. There is an example in the go programming language book by Alan A. A. Donovan and Brian W. Kernighan with exactly this construct. That example sorts music record by different fields, e.g., by year, by artist, etc. In order to use the sort.Sort API,
func Sort(data Interface)
The input data needs to have three methods
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
One way to sort by different fields is to define one custom data type for each case, say ByYear
, ByArtist
, etc. And define all three API methods for each case. But Len
and Swap
methods are redundant for all cases. A better solution is to define only one custom data type with a function member,
//!+customcode
type customSort struct {
t []*Track
less func(x, y *Track) bool
}
func (x customSort) Less(i, j int) bool {
return x.less(x.t[i], x.t[j]) }
func (x customSort) Len() int {
return len(x.t) }
func (x customSort) Swap(i, j int) {
x.t[i], x.t[j] = x.t[j], x.t[i] }
Then you can programmically control what less
means.
The source code is here
Upvotes: 2
Reputation: 3424
An interface should work here.
creating an interface like
type Stateful interface {
State() string
}
and a base state type
type BaseState struct{
}
func (s BaseState) State() string{
return "Base state"
}
you can imbed the BaseState
struct
type MyStruct struct{
BaseState
}
so that State
Will return "Base state"
, but can also implement its own method.
func (s MyStruct) State() string{
return "New State"
}
and now State
will return "New State"
https://play.golang.org/p/QOajW0O6gIz
Upvotes: 3