Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 如何检查混凝土类型由哪些嵌入类型组成?_Go_Composition_Embedding - Fatal编程技术网

Go 如何检查混凝土类型由哪些嵌入类型组成?

Go 如何检查混凝土类型由哪些嵌入类型组成?,go,composition,embedding,Go,Composition,Embedding,我怀疑我是在试图用OOP的方式来表现自己,但我不知道该用什么成语来做我想做的事 我有一个消息结构,用于在客户机-服务器应用程序中传递数据: type Message struct { ID string `json:"id,omitempty"` Type string `json:"type"` Data interface{} `json:"data"` } 此处的数据可以是不同的内容,例如许多命令: type Command struct

我怀疑我是在试图用OOP的方式来表现自己,但我不知道该用什么成语来做我想做的事

我有一个消息结构,用于在客户机-服务器应用程序中传递数据:

type Message struct {
    ID   string      `json:"id,omitempty"`
    Type string      `json:"type"`
    Data interface{} `json:"data"`
}
此处的数据可以是不同的内容,例如许多命令:

type Command struct {
    User *types.UserInfo `json:"user"`
}

type CommandA struct {
    Command
    A *AData `json:"a_data"`
}

type CommandB struct {
    CommandB
    B *BData `json:"b_data"`

}
我想做的是检查消息数据类型是否为命令,并执行所有命令共有的操作,例如授权,全部在一个位置,不必输入断言命令类型,调用适当的处理函数,然后执行身份验证,因为这将导致大量代码重复

下面的代码反映了我希望发生的事情

for {
    select {
    case m := <-in:
      // what I would like to do, obviously not working as
      // m.Data is not of type Command but the actual command type
      if c, ok := m.Data.(msg.Command); ok {
        // do auth and other common stuff
      }
      switch t := m.Data.(type) {
      case *msg.CommandA:
        go srv.handleCommandA(m.ID, t)
      case *msg.CommandB:
        go srv.handleCommandB(m.ID, t)
      // etc etc
      default:
        // do something
      }
   }
}
用于{
挑选{

案例m:=一种方法是使用反射从
数据
中提取公共字段值。在您的示例中,由于所有
命令
都有
用户
字段,我们可以使用它来识别
消息。数据
是否是命令。如果
命令
未嵌入到数据中,只需返回
nil
示例代码:

func GetUserInfo(v interface{}) *types.UserInfo {
    vt := reflect.ValueOf(v)
    if vt.Kind() == reflect.Ptr {
        vt = vt.Elem()
    }
    if vt.Kind() != reflect.Struct {
        return nil
    }

    u := vt.FieldByName("User")
    if !u.IsValid() {
        return nil
    }

    user, ok := u.Interface().(*types.UserInfo)
    if !ok {
        return nil
    }

    return user
}

//Call GetUserInfo then perform common operation
user := GetUserInfo(m.Data)
if user != nil {
    //Do auth and other common stuff
}

您可以在界面中定义通用命令

type Commander interface{
    DoCommonStuff()
}
为命令结构实现它

func (c Command) DoCommonStuff(){
//do stuff
}
然后断言

if c, ok := m.Data.(Commander); ok {
    c.DoCommonStuff()
}

您的其他代码应保持不变

,如果您知道
数据
始终是某种命令,则可以将结构中的类型更改为
Commander
,并消除类型断言,并获得某种类型的安全性来引导。