在 Go 中有点 "method overloading"?
Kinda "method overloading" in Go?
假设我有一个名为 State
:
的类型
type State struct {
// ... does not matter what is inside
}
连同其上定义的方法:
func (s *State) prettyName() string {
return "I am a state!"
}
目前我无法改变 prettyName()
的行为。我知道 Go
有意避开类似 OOP 的继承和方法重载,这可能永远不会改变,但仍然:如果我需要 prettyName()
根据任何因素做出不同的行为怎么办?我看到的唯一解决方案是:
type State struct {
_prettyName func() string
}
func (s *State) prettyName() string {
return s._prettyName()
}
是否有更好的 Go
式方法来实现相同的目标?
这里应该有一个接口。
创建类似
的界面
type Stateful interface {
State() string
}
和一个基础状态类型
type BaseState struct{
}
func (s BaseState) State() string{
return "Base state"
}
您可以嵌入 BaseState
结构
type MyStruct struct{
BaseState
}
所以State
会return"Base state"
,但也可以实现自己的方法。
func (s MyStruct) State() string{
return "New State"
}
现在 State
将 return "New State"
除了 prettyName
作为 struct
上的方法,您还可以定义函数类型的成员值。
type State struct {
prettyName func() string
}
然后你可以在运行时将它的值设置为任何函数
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())
这个例子在 playground
现在您可以使用 PrettyName
API 定义接口类型,进一步的 algorithms/business 逻辑将调用 PrettyName
。
type StateAPI interface {
PrettyName () string
}
要使 State
类型适合 StateAPI
接口,您需要围绕私有函数成员
定义一个简单的 PrettyName
方法
func (s *State) PrettyName() string {
return s.prettyName()
}
这基本上是您的原创想法,完全合法。 go programming language book by Alan A. A. Donovan and Brian W. Kernighan 中有一个示例正是采用这种结构。
该示例按不同字段对音乐记录进行排序,例如按年份、按艺术家等。为了使用 sort.Sort API、
func Sort(data Interface)
输入数据需要有三种方法
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)
}
按不同字段排序的一种方法是为每种情况定义一种自定义数据类型,例如 ByYear
、ByArtist
等。并为每种情况定义所有三种 API 方法案件。但是 Len
和 Swap
方法对于所有情况都是多余的。更好的解决方案是只定义一个带有函数成员的自定义数据类型,
//!+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] }
然后您可以通过编程控制 less
的含义。
源代码为here
假设我有一个名为 State
:
type State struct {
// ... does not matter what is inside
}
连同其上定义的方法:
func (s *State) prettyName() string {
return "I am a state!"
}
目前我无法改变 prettyName()
的行为。我知道 Go
有意避开类似 OOP 的继承和方法重载,这可能永远不会改变,但仍然:如果我需要 prettyName()
根据任何因素做出不同的行为怎么办?我看到的唯一解决方案是:
type State struct {
_prettyName func() string
}
func (s *State) prettyName() string {
return s._prettyName()
}
是否有更好的 Go
式方法来实现相同的目标?
这里应该有一个接口。
创建类似
的界面type Stateful interface {
State() string
}
和一个基础状态类型
type BaseState struct{
}
func (s BaseState) State() string{
return "Base state"
}
您可以嵌入 BaseState
结构
type MyStruct struct{
BaseState
}
所以State
会return"Base state"
,但也可以实现自己的方法。
func (s MyStruct) State() string{
return "New State"
}
现在 State
将 return "New State"
除了 prettyName
作为 struct
上的方法,您还可以定义函数类型的成员值。
type State struct {
prettyName func() string
}
然后你可以在运行时将它的值设置为任何函数
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())
这个例子在 playground
现在您可以使用 PrettyName
API 定义接口类型,进一步的 algorithms/business 逻辑将调用 PrettyName
。
type StateAPI interface {
PrettyName () string
}
要使 State
类型适合 StateAPI
接口,您需要围绕私有函数成员
PrettyName
方法
func (s *State) PrettyName() string {
return s.prettyName()
}
这基本上是您的原创想法,完全合法。 go programming language book by Alan A. A. Donovan and Brian W. Kernighan 中有一个示例正是采用这种结构。 该示例按不同字段对音乐记录进行排序,例如按年份、按艺术家等。为了使用 sort.Sort API、
func Sort(data Interface)
输入数据需要有三种方法
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)
}
按不同字段排序的一种方法是为每种情况定义一种自定义数据类型,例如 ByYear
、ByArtist
等。并为每种情况定义所有三种 API 方法案件。但是 Len
和 Swap
方法对于所有情况都是多余的。更好的解决方案是只定义一个带有函数成员的自定义数据类型,
//!+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] }
然后您可以通过编程控制 less
的含义。
源代码为here