Fsharp 记录中的可选参数

Optional parameters in Fsharp records

我需要为我的 F Sharp 记录修改和添加新的 属性。但随后它会给出没有这个新字段的先前实例的错误。我把它设置为 Nullable ,但仍然出现同样的错误,请帮我解决这个问题

我想你的意思是 "optional" 和 "a field that I don't provide when instantiating the record" 一样。但是,不幸的是(或者幸运的是,取决于您的观点),F# 记录中没有可选字段这样的东西。您指定的所有记录字段 必须 在实例化时出现。

另见 this closely related question

你可以考虑这个权衡:

  • 使用 记录。每次更新记录时,F# 编译器都会尖叫并提醒您使用该记录的所有地方,您现在需要提供附加信息。如果您添加的字段是选项,则附加信息可以是 None。最大的优势:您的代码本身不必处理所有可能的 "what to do if field1 is missing? What if field2 is missing, too?"

  • 情况
  • 使用一个class。当您更新 class 时,F# 编译器不会对您放入 class 中的信息强制执行任何类型的完整性检查。 (您可以将记录视为 classes,其中所有字段都是构造函数参数,并且必须提供所有字段)。因此,更新 class 定义不会产生任何开销,但您的代码需要处理所有缺失值。

我个人更喜欢记录,因为它迫使我思考添加新字段的含义。

当然有一个中间立场:您可以使用记录,但通过静态成员或类似的东西实例化所有记录:

type Name = 
    { 
        First: string
        Family: string
    }        
    static member Create(first, family) = { First = first; Family = family}

如果在您的代码中,您总是使用 Name.Create 来实例化记录,您当然可以添加一个 MiddleName 字段,而不会引起任何消费者代码的注意。

Option type 在 F# 中优于 null,原因很简单 "uninitialized variables" 在函数式思维方式中不存在。

让我们先建立一个代表 VacationRequest 的记录,它必须得到老板的批准。

type VacationRequest =
   {Name : string
    Date : DateTime
    Approval : string option}

你的方法的问题是所有字段都必须在构造时分配,所以这不会编译:

let holiday =
   {Name = "Funk"
    Date = DateTime(2020,12,31)}

您可以使用辅助函数解决此问题,该函数隐式设置选项值。

let fillInRequest name date =
   {Name = name 
    Date = date 
    Approval = None}

现在您可以使用辅助函数构建记录。

let holiday = fillInRequest "Funk" <| DateTime(2020,12,31)

将代码发送给 FSI 时注意到一些有趣的事情。

val holiday : VacationRequest = {Name = "Funk";
                                 Date = 31/12/2020 12:00:00 ;
                                 Approval = null;}

老板然后可以更新请求(创建 记录)

let approvedHoliday =
    {holiday with Approval = Some "boss' name"}
val approvedHoliday : VacationRequest = {Name = "Funk";
                                         Date = 31/12/2020 12:00:00 ;
                                         Approval = Some "boss' name";}

或原样发回

let betterLuckNextTime = holiday