简体   繁体   English

将 golang 结构定义为具有任意字段的类型?

[英]Define golang struct as type with arbitrary fields?

I'm very new to golang and the use of interfaces more generally.我对 golang 和更普遍的接口使用非常陌生。 I've stubbed out some code here:我在这里删除了一些代码:

type Alerter interface {
    Alert()
}

type AlertConfig struct{}

type Alert struct {
    Config *AlertConfig
}

type AlertConfigurator interface {
    UpdateConfig(key, value interface{}) (*AlertConfig, error)
}

type EmailAlertConfig AlertConfig {
    Recipients []mail.Address,
}

type HTTPAlertConfig AlertConfig {
    Method string
    TargetURL url.URL
}

type HTTPAlert struct {
    Config *HTTPAlertConfig
}

type EmailAlert struct {
    Config *EmailAlertConfig
}

func (ea *EmailAlert) Alert() {
    // this would actually send an email using data in its Config
    return
}

func (ha *HTTPAlert) Alert() {
    // this would actually hit an HTTP endpoint using data in its Config
    return
}

I'm sure I have all kinds of assumptions & biases that are hobbling my ability to express what I want to accomplish with this:我确信我有各种各样的假设和偏见,这些假设和偏见阻碍了我表达我想要完成的目标的能力:

I want to create different types of "Alert"s.我想创建不同类型的“警报”。 Any alert I create should have an "Alert()" method that triggers the Alert to actually do something (send an email, or POST to a URL, for example.我创建的任何警报都应该有一个“Alert()”方法来触发警报以实际执行某些操作(例如,发送 email 或 POST 到 URL。

The trouble comes in representing an Alert's "Config".问题在于表示警报的“配置”。 Different Alerts have different fields in their Configs.不同的警报在其配置中有不同的字段。 However, for each Alert type, specific fields are required to be there.但是,对于每种警报类型,需要有特定的字段。 To accomplish that I wanted to create a base type "AlertConfig" as a struct with arbitrary fields, then define, say, EmailAlertConfig as type 'AlertConfig', but having these specific fields, and then type 'HTTPAlertConfig' as type 'AlertConfig' requiring different fields.为了实现这一点,我想创建一个基本类型“AlertConfig”作为具有任意字段的结构,然后将EmailAlertConfig定义为类型“AlertConfig”,但具有这些特定字段,然后键入“HTTPAlertConfig”作为“AlertConfig”类型,需要不同的领域。 This way, I can define the 'Alert' type as having a field 'Config *AlertConfig'.这样,我可以将“Alert”类型定义为具有“Config *AlertConfig”字段。

I can almost emulate what I want if AlertConfig is defined as map[string]interface{}, but in this case I can't leverage golang's checking to validate that an EmailConfig has the required fields.如果 AlertConfig 被定义为 map[string]interface{},我几乎可以模拟我想要的,但在这种情况下,我无法利用 golang 的检查来验证 EmailConfig 是否具有必需的字段。

It seems pretty clear that I'm thinking about this the wrong way.很明显,我正在以错误的方式思考这个问题。 I could use a hand in getting on the right track & appreciate your advice.我可以帮助您走上正确的道路并感谢您的建议。

One way to deal with this problem is to leave configs as purely implementation specific:处理此问题的一种方法是将配置保留为纯实现特定的:

type HTTPAlert struct {
  Config *HTTPAlertConfig
}

func (a *HTTPAlert) Alert() {...}

type EmailAlert struct {
  Config *EmailAlertConfig
}

func (e *EmailAlert) Alert() {...}


With this implementation, the actual Alert implementation can use the type-specific alert configuration, leaving the problem of initializing the config.有了这个实现,实际的Alert实现可以使用特定类型的警报配置,留下初始化配置的问题。

When you create the instance of an alert, you can perform type-specific initialization.创建警报实例时,可以执行特定于类型的初始化。 For instance:例如:

var alerts = map[string]func(configFile string) Alert {
   "htmlAlert": NewHTMLAlert,
   "emailAlert" NewEmailAlert,
}

func NewHTMLAlert(configFile string) Alert {
  var alert HTMLAlert
  // Read file, initialize alert
  return &alert
}
...

Declare a type with the common fields:用公共字段声明一个类型:

 type AlertConfig struct { 
    ExampleCommonField string
 }

Embed that type in actual configurations:将该类型嵌入到实际配置中:

type HTTPAlertConfig struct {
    AlertConfig
    Method string
    TargetURL url.URL
}

Based on the code in the question, the alert and config types can be combined.根据问题中的代码,可以结合使用警报和配置类型。

func (ha *HTTPAlertConfig) Alert() {
    // this will hit an HTTP endpoint using data in the receiver
    return
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM