如何使用派生类型进行sync.Map

时间:2017-11-08 11:42:15

标签: go

我的目标是拥有一个我可以派生的自定义类型并添加额外的方法,例如,当使用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)

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

  

The Go Programming Language Specification

     

Struct types

     

结构是一系列命名元素,称为字段,每个元素   它有一个名称和类型。可以明确指定字段名称   (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

     

Selectors

     

对于不是包名称的主表达式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.LoadOrStorex.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根据现有类型定义新类型。

根据Language Specification

  

已定义的类型可能包含与之关联的方法。它不是   继承绑定到给定类型的任何方法

这意味着,myMap只会继承sync.Map(这是struct)但不是它的方法的字段。它不像其他语言中的类继承一样工作。

具体来说,sync.Map没有任何导出字段,因此使用它来定义新类型是没有意义的。 相反,您应该将包含struct的{​​{1}}类型定义为字段。然后您就可以访问它的方法了。 @ peterSO的答案显示了如何做到这一点。