问题 榆树中的不透明类型是什么?为什么它有价值?


我之前使用过类型,但不知道opaque类型是什么。我也看过它。暴露opaque类型而不是类型别名更好吗?


9805
2017-11-24 20:55


起源



答案:


让我们首先看一下类型别名来回答这个问题:

类型别名是完全透明的。这意味着导入它的任何其他模块都可以完全访问其内部工作。假设我们有一个 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 函数,不需要知道类型中的数据
  • 可以在不破坏包含模块之外的代码的情况下更新类型

大部分解释都来自于此 @wintveltelmlang.slack.com


14
2017-11-24 20:55



以下是有关该值的库和包的作者的更多讨论: package.elm-lang.org/help/... - Nathan
感谢分享这个解释。因为大约一半是我之前在Slack上发布的答案的精确副本(这里),提及或链接会很好。 - wintvelt
嘿@wintvelt:对不起!我认为这是一个非常好的答案,有助于生活在一个更永久的地方。我添加了对您的SO帐户的引用。也许SO mod可以将你添加为作者? - Nathan
谢谢你的提及。欣赏它。在这种情况下的常见做法是 - 我认为 - 至少添加一个链接到您的源(链接已经在我的评论:)。 - wintvelt


答案:


让我们首先看一下类型别名来回答这个问题:

类型别名是完全透明的。这意味着导入它的任何其他模块都可以完全访问其内部工作。假设我们有一个 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 函数,不需要知道类型中的数据
  • 可以在不破坏包含模块之外的代码的情况下更新类型

大部分解释都来自于此 @wintveltelmlang.slack.com


14
2017-11-24 20:55



以下是有关该值的库和包的作者的更多讨论: package.elm-lang.org/help/... - Nathan
感谢分享这个解释。因为大约一半是我之前在Slack上发布的答案的精确副本(这里),提及或链接会很好。 - wintvelt
嘿@wintvelt:对不起!我认为这是一个非常好的答案,有助于生活在一个更永久的地方。我添加了对您的SO帐户的引用。也许SO mod可以将你添加为作者? - Nathan
谢谢你的提及。欣赏它。在这种情况下的常见做法是 - 我认为 - 至少添加一个链接到您的源(链接已经在我的评论:)。 - wintvelt