2016-11-24 55 views

回答

13

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

类型别名是完全透明的。这意味着任何其他导入它的模块都可以完全访问其内部工作。比方说,我们已经有了一个User模块露出User类型:

module User exposing User 

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

任何人进口User可以操纵数据,例如newUser = { oldUser | age = 25 }。或者做someUser = User "Bill" 27。当您控制它们存在的上下文时,这些操作很好。

但是,如果User是库的一部分,那么对User类型的每次更改都会对使用该库的人造成重大改变。例如,如果在User中添加了email字段,则构造函数示例(someUser = User "Bill" 27)会给出编译器错误。

即使在项目代码库的内部,类型别名也可以向其他模块提供太多信息,从而导致难以维护和发展的代码。在某些时候,User可能会发生急剧变化,并具有一组全新的属性。无论代码如何处理User s,都需要进行更改。

不透明类型是有价值的,因为它们可以避免这些问题。下面是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功能,不需要知道的是在类型
  • 类型可以不破坏模块包含

之外的代码更新哪些数据210

这在很大程度上解释来自@wintveltelmlang.slack.com

+0

下面是库的作者和包约值一些更多的讨论:http://package.elm-lang.org/help/design-guidelines#keep-tags -and-record-constructors-secret – Nathan

+0

感谢分享这个解释。因为它的大约一半是我早些时候在Slack([这里](https://elmlang.slack.com/archives/design-patterns/p1480011953000265))上发布的答案的确切副本,所以提及或链接应该是不错。 – wintvelt

+1

嘿@wintvelt:对不起!我认为这是一个非常好的答案,有助于生活在更加持久的地方。我为您的SO帐户添加了一个参考。也许一个SO MOD可以将你添加为作者? – Nathan