我的目标是拥有一个我可以派生的自定义类型并添加额外的方法,例如,当使用map时,这可行:
package main
import "fmt"
type myMap map[string]string
func (m *myMap) Add() {
_, ok := (*m)["test"]
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
但是如果想和sync.Map一样想怎么做呢?我目前正在尝试这样做:https://play.golang.org/p/8PjpPY-Sjq
package main
import (
"fmt"
"sync"
)
type myMap sync.Map
func (m *myMap) Add() {
_, ok := (*m).Load("test")
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
但是得到这个错误:
(*m).Load undefined (type myMap has no field or method Load)
有什么想法吗?
答案 0 :(得分:4)
The Go Programming Language Specification
结构是一系列命名元素,称为字段,每个元素 它有一个名称和类型。可以明确指定字段名称 (IdentifierList)或隐式(EmbeddedField)。在结构中, 非空白字段名称必须是唯一的。
StructType = "struct" "{" { FieldDecl ";" } "}" . FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . EmbeddedField = [ "*" ] TypeName . Tag = string_lit .
使用类型但没有显式字段名称声明的字段称为 嵌入式领域。必须将嵌入字段指定为类型名称T. 或者作为指向非接口类型名称* T的指针,而T本身可能不是 是指针类型。非限定类型名称用作字段名称。
调用struct x中嵌入字段的字段或方法f 如果x.f是表示该字段或方法的合法选择器,则提升 F。
提升字段的作用类似于结构的普通字段,但它们除外 不能在结构的复合文字中用作字段名称。
给定结构类型S和名为T的类型,提升的方法是 包含在结构的方法集中,如下所示:
如果S包含嵌入字段T,则S和* S的方法集都包括与接收方T的提升方法。* S的方法集 还包括带接收器* T的推广方法。
如果S包含嵌入字段* T,则S和* S的方法集都包括带有接收者T或* T的提升方法。
使用struct
的嵌入字段。例如,
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Load(k)
fmt.Println(k, v, ok)
}
游乐场:https://play.golang.org/p/YCNeiYVhlT
输出:
true
test 42 true
The Go Programming Language Specification
对于不是包名称的主表达式x,选择器 表达
x.f
表示值x的字段或方法f(或有时* x;参见 下面)。标识符f称为(字段或方法)选择器;它 不能是空白标识符。选择器表达式的类型 是f的类型。如果x是包名称,请参阅有关限定的部分 标识符
选择器f可以表示类型T的字段或方法f,或者它可以 参考T的嵌套嵌入字段的字段或方法f 遍历到f的嵌入字段的数量称为其深度 T.在T中声明的字段或方法f的深度为零。深度 在T中的嵌入字段A中声明的字段或方法f是 A加1的f深度。
规则1:
对于类型为T或* T的值,其中T不是指针或接口 type,x.f表示T中最浅深度处的字段或方法 哪里有这样的f。如果没有一个f 最浅的深度,选择器表达式是非法的。
有时,嵌套嵌入的复杂情况存在歧义。如果是,请明确指定完整限定符。例如,m.Map.LoadOrStore
和x.Map.Load
。
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.Map.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Map.Load(k)
fmt.Println(k, v, ok)
}
答案 1 :(得分:2)
行:type myMap sync.Map
根据现有类型定义新类型。
已定义的类型可能包含与之关联的方法。它不是 继承绑定到给定类型的任何方法
这意味着,myMap
只会继承sync.Map
(这是struct
)但不是它的方法的字段。它不像其他语言中的类继承一样工作。
具体来说,sync.Map
没有任何导出字段,因此使用它来定义新类型是没有意义的。
相反,您应该将包含struct
的{{1}}类型定义为字段。然后您就可以访问它的方法了。 @ peterSO的答案显示了如何做到这一点。