go - 在 Go 中使用新类型包装器作为 ID 是惯用的吗?

标签 go idioms newtype

在 Haskell、Scala 或 Rust 等其他静态类型语言中,有时对于标识符之类的东西,人们会将它们包装在特殊类型中以帮助编译器捕获错误(例如,防止您传递另一个范围内的 String)并通过在类型级别编码责任来提高代码的可读性。

一些例子:

newtype UserId = UserId Integer

case class UserId(value: Long) extends AnyVal

struct UserId(u64);

所有这些(通常)都没有运行时成本,并且几乎不会增加困惑,从而提高了安心感,并在类型级别提供了开发时文档。

Go也有这个能力:

type UserId uint64

我的问题不是这是否可能,而是这在 Go 中是否广泛和/或被认为是惯用的,以及为什么。

最佳答案

Go 支持 type inference在编译器级别。编译的二进制文件没有运行时成本。

使用此类型定义

type UserID uint64

以下两项都应生成相同的二进制文件:

uid := UserID(1)
var uid UserID = 1

根据我的经验,开发环境可以同样很好地理解两者。而且它们都是人类可读的。我认为我在生产代码中看到的第一个代码比第二个代码更多。

正如 @AndySchweig 在评论中提到的,这通常在变量是类似 Enum 的值时使用。

type UserType uint

const (
  TypeVisitor UserType = 1
  TypeNormal = 2
  TypeAdmin = 3
)

type UserType uint

const (
  TypeVisitor UserType = iota
  TypeNormal
  TypeAdmin
)

导出的 const 将使代码更具可读性:


switch userType {
  case mylib.TypeVisitor:
    // do something
  case mylib.TypeNormal:
    // do something
  case mylib.TypeAdmin:
    // do something
}

关于go - 在 Go 中使用新类型包装器作为 ID 是惯用的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58386332/

相关文章:

rust - 读取文件并获取字符串数组

haskell - 隐式类型强制?

mysql - 使用 Go 和 MySQL 设置具有容错能力的服务器(故障转移)

go - 根据 Go lang 中的类型处理案例的更好方法

go - 如何实现文件系统?

go - 如何使用GoQuery查找具有特定ID的元素

rust - 计数选项集合中出现次数的惯用方式

mysql - 需要 MySQL 惯用法来检查字符串是否包含一组字符中的任何一个

haskell - 为什么状态单子(monad)通常使用 newtype 而不是 type

haskell - 未装箱类型的限制