什么是Elm中的不透明类型,它有什么价值?

16

我之前使用过类型(type),但不知道什么是不透明类型(opaque type),我也看到它被提到过。暴露不透明类型是否比类型别名更好?

1个回答

20

首先让我们看一下类型别名:

类型别名是完全透明的。这意味着任何导入它的其他模块都可以完全访问它的内部结构。假设我们有一个“User”模块,公开了一个“User”类型:

module User exposing User

type alias User =
    { userName : String
    , age : Int
    }

引入User的任何人都可以操纵数据,例如newUser = { oldUser | age = 25 }。或者执行someUser = User "Bill" 27。当您控制它们存在的上下文时,这些操作是可以接受的。

然而,如果User是库的一部分,那么对User类型的每个更改对使用该库的人来说都是一个破坏性的变化。例如,如果添加了email字段到User,那么构造函数示例(someUser = User "Bill" 27)将会产生编译器错误。

即使在项目代码库内部,类型别名也可能向其他模块提供过多信息,导致难以维护和演进的代码。也许User在某些时候发生了巨大变化,并具有完全新的属性集。这将要求更改代码操纵User的任何地方。

不透明类型很有价值,因为它们避免了这些问题。这里是一个User的不透明版本:

module User exposing User

type User =
    User
        { userName : String
        , age : Int
        }

使用此版本,其他模块无法直接访问或操作数据。通常,这意味着您将创建并公开一些getter和函数:

initUser : String -> Int -> User
userName : User -> String
age : User -> String
setAge : Int -> User -> User

这样做更加繁琐,但有以下好处:

  • 其他模块只需关注User函数,并且不需要知道类型中包含了哪些数据
  • 可以更新该类型而不会破坏容器模块之外的代码

大部分解释来自@wintvelt: elmlang.slack.com


这是一些面向库和包的作者关于价值的讨论:http://package.elm-lang.org/help/design-guidelines#keep-tags-and-record-constructors-secret - Nathan
感谢分享这个解释。因为其中大约一半是我之前在Slack上发布的答案的完全复制(在此处),提及或链接会更好。 - wintvelt
1
嘿 @wintvelt:抱歉!我以为这是一个非常好的答案,对于在一个更永久的地方生活会有帮助。我已经在你的SO账户上添加了参考。也许一个SO的管理员可以将你添加为作者? - Nathan
感谢提及,非常感谢。在这种情况下的通常做法是-我认为-至少添加一个指向您来源网站的链接(链接已在我的评论中:)。 - wintvelt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接