如何使用派生类型进行sync.Map
My goal is to have a custom type the one I could derive and add extra methods, for example, when using a map this works:
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
", x)
}
But if want the same with sync.Map how to do it? I am currently trying this: 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
", x)
}
But get this error:
(*m).Load undefined (type myMap has no field or method Load)
Any ideas?
The Go Programming Language Specification
A struct is a sequence of named elements, called fields, each of which has a name and a type. Field names may be specified explicitly (IdentifierList) or implicitly (EmbeddedField). Within a struct, non-blank field names must be unique.
StructType = "struct" "{" { FieldDecl ";" } "}" . FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . EmbeddedField = [ "*" ] TypeName . Tag = string_lit .
A field declared with a type but no explicit field name is called an embedded field. An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.
A field or method f of an embedded field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.
Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.
Given a struct type S and a type named T, promoted methods are included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
Use an embedded field of a struct
. For example,
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)
}
Playground: https://play.golang.org/p/YCNeiYVhlT
Output:
true
test 42 true
The Go Programming Language Specification
For a primary expression x that is not a package name, the selector expression
x.f
denotes the field or method f of the value x (or sometimes *x; see below). The identifier f is called the (field or method) selector; it must not be the blank identifier. The type of the selector expression is the type of f. If x is a package name, see the section on qualified identifiers.
A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T. The number of embedded fields traversed to reach f is called its depth in T. The depth of a field or method f declared in T is zero. The depth of a field or method f declared in an embedded field A in T is the depth of f in A plus one.
Rule 1:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
Sometimes, there is ambiguity in complex cases of nested embedding. If so, specify the full qualifiers explicitly. For example, m.Map.LoadOrStore
and 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)
}
The line: type myMap sync.Map
defines a new type based on an existing type.
According to the Language Specification:
A defined type may have methods associated with it. It does not inherit any methods bound to the given type
It means, that myMap
only inherits the fields of sync.Map
(which is a struct
) but not it's methods. It doesn't work like class inheritance in other languages.
Specifically, sync.Map
does not have any exported fields, so using it to define a new type is pointless.
Instead you should define a struct
type that contains sync.Map
as a field. Then you'll have access to it's methods. @peterSO's answer shows how to do that.