返回匿名记录而不是元组的警告

时间:2019-01-22 14:58:06

标签: f# record anonymous-types

考虑以下(通用的,可以在库中公开)实用程序函数,该函数将字符串解析为HTTP Basic凭证并返回用户名和密码:

let parseBasicCredentials (encodedCredentials: string) =
  (* approx. 10 lines of pipes, matching and try/with *)
  username, password

由于用户名和密码都是字符串,因此调用者需要记住(或检查文档)用户名作为元组的第一个元素,而密码作为第二个元素。

但是,F#很快将获得对匿名记录的支持(已经在夜间使用)。发生这种情况时,此类函数还可以返回匿名记录:

let parseBasicCredentials (encodedCredentials: string) =
  (* approx. 10 lines of pipes, matching and try/with *)
  {| Username = username; Password = password |}

这似乎很好用,但是由于这是一种全新的语言功能,因此我不确定这是否存在任何弊端,无论是技术上的还是简单地皱着眉头。 AFAIK返回元组是诸如此类的简单辅助函数的惯用且可接受的解决方案。匿名类型还可以让您命名元素,因此可以更加“安全”,因为它具有更多的自记录性,因此可以更好地防止调用者混淆返回的值。

我不考虑通用(非域)辅助函数,例如用于返回单独定义的记录类型的候选对象,或单格DU的元组。我只是很好奇,既然存在匿名记录,当一个人需要临时的,非原始的返回值(例如此处)时它们是否可以充当“更好的元组”,或者在某种程度上仍首选元组(如果需要,元组)原因)。

1 个答案:

答案 0 :(得分:2)

我很少使用匿名记录,但我相信主要限制是您不能编写将它们用作输入的函数。这严重限制了它们在功能之间传递的应用程序范围数据的使用,这是有意的设计选择。

它们将更方便地用作在函数或脚本文件中存储瞬态数据的便捷方式。

更正:

可以将它们作为输入。这是一个示例:

let showCredentials (x:{| Username:string; Password:string |}) =
    printfn "Username: %s, Password %s" x.Username x.Password

但是,您必须提及记录中的所有字段,以使其与类型匹配。因此,要编写另一个接受相同类型但不使用密码的函数,您可以这样编写:

let showUsername (x:{| Username:string; Password:_ |}) =
    printfn "Username: %s" x.Username

这意味着每次您完全编辑类型定义时,都必须编辑该类型的函数参数的所有类型注释。不能很好地扩展到一般用途。

可能会添加模式匹配,因此您可以编写:

let showUsername {| Username = username |} =
    printfn "Username: %s" username

但是我不清楚这是否要添加到语言中。