代码之家  ›  专栏  ›  技术社区  ›  cmeeren

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

  •  4
  • cmeeren  · 技术社区  · 6 年前

    考虑以下(常规,可以在库中公开)实用程序函数,用于将字符串解析为HTTP基本凭据并返回用户名和密码:

    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 回复  |  直到 6 年前
        1
  •  2
  •   TheQuickBrownFox    6 年前

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

    作为在函数或脚本文件中存储瞬态数据的一种方便方法,它们将更加有用。

    更正:

    可以将它们作为输入。下面是一个例子:

    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
    

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