如何将interface{}用作通配符类型?

huangapple go评论81阅读模式
英文:

How can I use interface{} as a wildcard type?

问题

场景是传递具有共同字段的类似结构,并将其设置为作为参数传递的值:

package main

type A struct {
    Status int
}

type B struct {
    id     string
    Status int
}

// 可以通过值传递,因为内容仅在此函数内部使用
func foo(v interface{}, status int) {
    switch t := v.(type) {
    case A, B:
        t.Status = status // 错误 :-(
    }
}

func main() {
    a := A{}
    foo(a, 0)
    b := B{}
    b.id = "x"
    foo(b, 1)
}

令我沮丧的是,我得到了这个错误:

# command-line-arguments
./test.go:15: t.Status undefined (type interface {} has no field or method Status)

如果类型转换将 interface{} 转换为底层类型,那么我做错了什么?

英文:

The scenario is to pass similar structs with common fields and set those to values passed as params:

package main

type A struct {
	Status int
}

type B struct {
	id     string
	Status int
}

// It's okay to pass by value because content is only used inside this
func foo(v interface{}, status int) {
	switch t := v.(type) {
	case A, B:
		t.Status = status // ERROR :-(
	}
}

func main() {
	a := A{}
	foo(a, 0)
	b := B{}
	b.id = "x"
	foo(b, 1)
}

To my dismay, I am getting this error:

➜  test  go run test.go
# command-line-arguments
./test.go:15: t.Status undefined (type interface {} has no field or method Status)

What am I doing wrong if the typecast converts interface{} to the underlying type?

答案1

得分: 5

即使A和B都有一个状态字段,它们在类型系统中并不可互换。你必须为它们分别设置不同的情况。

case A:
    t.Status = status
case B:
    t.Status = status
}

playground链接

或者,你可以使用一个实际的接口:

type HasStatus interface {
    SetStatus(int)
}

type A struct {
    Status int
}

func (a *A) SetStatus(s int) { a.Status = s }

func foo(v HasStatus, status int) {
    v.SetStatus(status)
}

完整示例

如果你有多个类型都有一组共同的字段,你可以使用嵌入结构体:

type HasStatus interface {
    SetStatus(int)
}

type StatusHolder struct {
    Status int
}

func (sh *StatusHolder) SetStatus(s int) { sh.Status = s }

type A struct {
    StatusHolder
}

type B struct {
    id string
    StatusHolder
}

完整示例

英文:

Even though A and B both have a status field they are not interchangeable to the type system. You must have separate cases for each of them.

case A:
	t.Status = status
case B:
	t.Status = status
} 

playground link

Alternatively, you could use an actual interface:

type HasStatus interface {
  SetStatus(int)
}

type A struct {
   Status int
}

func (a *A) SetStatus(s int) { a.Status = s }

func foo(v HasStatus, status int) {
	v.SetStatus(status)
}

full example

If you have multiple types that all have a common set of fields you may want to use an embedded struct:

type HasStatus interface {
	SetStatus(int)
}

type StatusHolder struct {
	Status int
}

func (sh *StatusHolder) SetStatus(s int) { sh.Status = s }

type A struct {
	StatusHolder
}

type B struct {
	id string
	StatusHolder
}

full example

huangapple
  • 本文由 发表于 2015年7月29日 12:24:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/31691193.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定