英文:
Best practices to use own type in golang. Alians to build type
问题
我想知道在Go语言中何时或是否应该使用自定义类型。当这样做可以更容易理解我的代码时,或者当我不应该使用自定义类型时。
示例:
我想创建一个带有MAC和主机名的map
类型:
第一种方式是最简单的方式:
var machines map[string]string{
"11:22...": "myHost",
"22:33..": "yourHost",
}
第二种方式:
type MAC string
type HOST string
machines := map[MAC]HOST{
MAC("11:22.."): HOST("myHost"),
MAC("22:33.."): HOST("yourHost"),
}
在上面的示例中,我可以通过编写方法来对我的类型MAC
和HOST
进行额外的控制,例如验证、比较等,这样会更好吗?
第三种方式:
type MACHINES map[string]string
m := MACHINES{}
m = map[string]string{
"11:22..": "myHost",
"22:33": "yourHost",
}
对我来说,上面的示例更难理解,对其他人来说也不够直观。我认为上面的示例也应该涉及到HOST
和MAC
,因为类型MACHINE
并没有告诉开发者应该如何实现,所以我希望可以这样:
type MACHINES map[MAC]HOST
然而,请给出关于在Go语言中使用自定义类型的更好理解的注释。
英文:
I wonder when or if it should be use own type in golang. When this will be more friendly to understand my code, or when I shouldn't use own type.
Example:
I want to create map
type with MAC, and name host:
in first way the simplest I can do that
var machines map[string]string{
"11:22...": "myHost",
"22:33..": "yourHost",
}
in second way
type MAC string
type HOST string
machines := map[MAC]HOST{
MAC("11:22..") : HOST("myHost"),
MAC("22:33..") : HOST("yourHost"),
}
In above exmaple I can get additional controle on my type MAC
, HOST
trought write method to validation, compare etc it is better ?
Third way
type MACHINES map[string]string
m := MACHINES{}
m = map[string]string{
"11:22.." : "myHost",
"22:33" : "yourHost",
}
above example for me is worst to understand less intuitive to some else. I think that above example should be also filled about HOST, and MAC because type MACHINE nothing to say developer how this should be implement so I would like
type MACHINES map[MAC]HOST
However, please about comment to better understand about usage own type in golang.
答案1
得分: 5
不评论你具体的例子,一般来说有几个原因你会想要使用一个新的类型:
- 你需要在该类型上定义方法。
- 你不希望该类型可以与字面量或者与其派生类型的变量进行比较(例如,为了减少用户的困惑或确保他们不会做一些无效的操作,比如尝试将你的特殊字符串与其他随机字符串进行比较)。
- 你只是需要一个地方来放置文档,或者将返回特定类型的方法进行分组(例如,如果你有几个返回
net.Conn
的Dial方法,你可以创建一个type Conn net.Conn
,并返回它,仅仅是为了将这些函数在Conn类型的头部在godoc中进行分组,或者为返回的net.Conn提供一般性的文档)。 - 因为你希望人们能够检查某个泛型类型是否来自你的包(例如,即使你的Conn只是一个普通的net.Conn,它也给了你类型切换和检查它是否为yourpackage.Conn的选项)。
- 你希望一个函数接受预定义列表中的参数,并且不希望用户能够创建可以传递进去的新值(例如,一个未导出类型的导出常量列表)。
英文:
Without commenting on your specific example, there are a few reasons you'd generally want to use a new type:
- You need to define methods on the type
- You don't want the type to be comparable with literals or variables with the type it's derived from (eg. to reduce user confusion or make sure they don't do something invalid like attempt to compare your special string with some other random string)
- You just need a place to put documentation, or to group methods that return a specific type (eg. if you have several Dial methods that return a
net.Conn
, you might create atype Conn net.Conn
and return that instead just for the sake of grouping the functions under the Conn type header in godoc or to provide general documentation for the net.Conn returned by the methods). - Because you want people to be able to check if something of a generic type came from your package or not (eg. even if your Conn is just a normal net.Conn, it gives you the option of type switching and checking if it's a yourpackage.Conn as well)
- You want a function to take an argument from a predefined list of things and you don't want the user to be able to make new values that can be passed in (eg. a list of exported constants of an unexported type)
答案2
得分: 1
创建类型别名只在需要添加额外方法(如验证函数)或者想要记录某个值的预期用法(例如,net.IP 类型)时才有用。
类型别名可以帮助你避免 API 误解,但如果你使用的是常量值,则无法起到作用。例如,下面的代码是有效的:
type Host string
type Mac string
hosts := map[Mac]Host{"ad:cb..": "localhost"}
关于 Go 中常量的工作原理,你可以查看 Rob Pike 的博客文章。
英文:
Creating type alias is only useful when you require to add extra methods (such as validation functions) or when you want to document the desired use of some value (for example, the net.IP type).
Type alias could help you to prevent API misunderstanding, but won't if you're using constant values. For example, this code is valid:
type Host string
type Mac string
hosts := map[Mac]Host{"ad:cb..": "localhost"}
For further information about how constants work in Go, you can check the Rob Pike's blog post
答案3
得分: 0
Go语言中最重要的特性之一是接口(interfaces)。通过定义接口的方法,你可以实现接口,而实现接口的唯一方式是在类型中添加方法。例如,假设你想要实现fmt
包中的Stringer
接口。
在你的例子中,type MACHINES map[string]string
,你需要在你的类型中添加一个名为String
的方法。
func (m MACHINES) String() string {
s := "MACHINES\n"
for k, v := range m {
s += fmt.Sprintf("%v: %v\n", k, v)
}
return s
}
现在,任何接受Stringer
接口的函数也可以接受你的MACHINES
类型,因为你实现了Stringer
接口。
例如,fmt.Printf
函数会检查传入的类型是否实现了Stringer
接口。
m := MACHINES{"foo":"bar", "baz": "bust"}
fmt.Printf("%s", m)
将调用MACHINES
的String
方法。
你可以在playground中查看示例。
英文:
One of the most important features of Go is interfaces. In Go by defining the method/s of an Interface you implement the interface, and the only way to implement an interface is by adding a Method to your type. For instance, say you want to implement the Stringer
interface from the fmt
package.
In your example type MACHINES map[string]string
you would add a method called String
to your type.
func (m MACHINES) String() string {
s := "MACHINES\n"
for k, v := range m {
s += fmt.Sprintf("%v: %v\n", k, v)
}
return s
}
Any other function that accepts the Stringer
interfaces can now also accept your MACHINES type since you implemented the Stringer
interface.
For example the fmt.Printf
checks if the passed in type implements the Stringer
interface
m := MACHINES{"foo":"bar", "baz": "bust"}
fmt.Printf("%s", m)
Will invoke MACHINES String method
Example from the playground
答案4
得分: 0
在我看来,你确实应该使用自己的类型。
举个例子,所有参数都是“string”或“int”的函数参数列表很容易混淆,而且很容易出错。
关于你的类型名称,我有一点建议。"MAC"是媒体访问控制的首字母缩写,所以应该保持全大写。但是"HOST"应该改为"Host",因为它只是一个单词。我不记得具体在哪里,但是Go语言有一种推荐的命名形式,即驼峰命名法,其中包括全大写的缩写,比如"GetIPv4AddressFromDNS"。
英文:
You do want to use your own types in my opinion.
As an example, lists of function arguments that are all "string" or all "int" are confusing and very easy to get wrong.
And a comment on your type names. "MAC" is an acronym for Media Access Control so it should stay as all caps. But "HOST" should be "Host" since it is just a word. I don't recall where it is exactly, but there's a recommended form for Go names which is CamelCase with all-capital abbreviations, like "GetIPv4AddressFromDNS"
答案5
得分: 0
我认为使用自定义类型的另一个原因是,如果你不确定某个东西的正确类型,比如uint8 / uint16,而且你希望以后能够轻松地在一个地方进行更改。
然而,这将导致在使用内置类型的方法时需要进行转换。或者你需要在自定义类型上定义这些方法。
英文:
I think another reason to use your own types, that hasn't been mentioned here, is if you are not sure exactly what the right type for something is e.g. uint8 / uint16 and you want to easily change it later all in one place.
This will however make conversions necessary whenever you want to use the built-in types' methods. Or you will need to define them on your own type.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论