接口的同义结构字段和方法名称

接口的同义结构字段和方法名称

问题描述:

I'm building a type structure that represents some devices on my network. There are lots of types of these devices, such as:

type Foo struct  { ... }
type Bar struct  { ... }
type Spam struct { ... }

but they all share a few common fields, one of which is IP. I'd like to define Device as an interface so I can group these together logically

type Device interface {
    IP() string
    ...
}

type LogicalGrouping struct {
    Devices []Device
    ...
}

but I'm running into an error with overlapping names.

func (f *Foo) IP() string { return f.IP }  // same method name as field name

I can rename either the field or the method or both, but surely this must be a common use case -- grouping structs by the fields they have in common? Is there an idiomatic solution here?

我正在建立一个表示我网络上某些设备的类型结构。 这些设备的类型很多,例如: p>

  type Foo struct {...} 
type Bar struct {...} 
type Spam struct {..  } 
  code>  pre> 
 
 

,但是它们都共享一些公共字段,其中之一是 IP code>。 我想将 Device code>定义为接口,以便可以将它们逻辑上分组 p>

  type设备接口{
 IP()字符串
  ... 
} 
 
type LogicalGrouping结构{
 Devices [] Device 
 ... 
} 
  code>  pre> 
 
 

,但是我遇到了 p>

  func(f * Foo)IP()字符串{return f.IP} //与字段名相同的方法名称
  code>   pre> 
 
 

我可以重命名字段或方法,或同时重命名,但这肯定是常见的用例-按结构的共同字段对结构进行分组? 这里有惯用的解决方案吗? p> div>

The general rule of thumb is that interfaces define behaviours and fields define data.

The problem here is that you are using an interface to access data in fields. On it's own that's not necessarily a bad thing. But you might want to reconsider how to structure your code so that you don't get this collision.

The first question I would as is:

"Why do you need to export the field IP if the struct defines an IP() method that has access to it?"

You could make the struct field unexported i.e. ip not IP, and then in the place you are using struct.IP, use struct.IP() instead.

The second question is:

"If you have structs such as foo, bar, spam and they all share common fields, why not use composition to deduplicate the definition of those shared fields."

This would probably only work if you are really only after the data that's inside the struct, I would generally advocate for using interfaces in all cases.

If you have the following structs:

type Foo struct {
    IP string
    A string 
    B string
}

type Bar struct {
    IP string
    A string 
    B string
}

type Spam struct {
    IP string
    A string 
    B string
}

You could use a new struct to represent the fields they have in common, and anonymously compose that inside:

type Inner struct {
    IP string
    A string 
    B string
}

type Foo struct {
    Inner
}

type Bar struct {
    Inner
}

type Spam struct {
    Inner
}

In the function call where you were using struct.IP(), accept an Inner and call it with struct.Inner. You will still have access to struct.IP even though IP is defined inside Inner.

You also may consider option to have ip field and GetIP & SetIP methods (or IP & SetIP accordingly to this doc) - it's clear, concise and simple.