我想在实例化通用记录时显式地提供类型参数。换句话说,给定一个RecordType<'T1, 'T2, 'T3>
,我想通过指定这些通用参数来创建一个RecordType<'T1, 'T2, 'T3>
的实例,该实例具有固定的'T1
, 'T2
和'T3
。在f#中有办法做到这一点吗?
我看到三种情况下它是有用的:
-
当有多个泛型类型具有相同名称时实例化一条记录
假设我们有以下记录定义:
type SimpleGenericRecord<'T1, 'T2> = { f1 : 'T1 -> 'T2 } type SimpleGenericRecord<'T> = { f1 : 'T -> 'T }
我很容易构建
SimpleGenericRecord<'T>
的实例,它是最后一个定义:let record = { f1 = fun (x: int) -> 0 } let record1 = { SimpleGenericRecord.f1 = fun (x: int) -> 0 }
以下尝试创建
SimpleGenericRecord<int, int>
给出编译错误:let record2 = { SimpleGenericRecord<int, int>.f1 = fun (x: int) -> 0 } let record3 = { SimpleGenericRecord<_, _>.f1 = fun (x: int) -> 0 }
我知道对两种类型使用相同的记录名可能不是最好的主意,尽管如此,我认为语言应该给我一种使用这两种类型的方法。
-
记录类型
f#引用说:
不要对记录字段使用DefaultValue属性。一个更好的方法是定义带有字段的记录的默认实例初始化为默认值,然后使用复制和更新记录表达式以设置与默认值不同的任何字段值。
遵循这条建议,我想定义记录的默认实例,因为它们是公共API的一部分,记录它们的类型。
-
帮助进行类型推断
记录类型的泛型参数可用于推断记录值的类型。
假设我有:
type RecordWithSomeComplexType<'T> = { t1 : int -> System.Collections.Generic.Dictionary<int, 'T> // some long type signature }
,我想实例化它。如果我不提供任何类型注释,记录值将尽可能通用,例如
let record4 = { RecordWithSomeComplexType.t1 = failwith "Intentionally failing" }
有类型
int -> System.Collections.Generic.Dictionary<int, obj>
我可以强制记录为特定类型(例如
RecordWithSomeComplexType<string>
),但在这种情况下,我需要写特定值的完整类型,例如let failing = { RecordWithSomeComplexType.t1 = failwith "Intentionally failing" :> int -> System.Collections.Generic.Dictionary<int, string> // I don't want to provide a full type of a value here }
如果编译器知道我想要
RecordWithSomeComplexType<string>
,它可以推断值的签名
你几乎可以在任何地方添加类型注释
let record2 : SimpleGenericRecord<_, _> = {
f1 = fun (x: int) -> 0
}
// alternative
let record2 =
({
f1 = fun (x: int) -> 0
} : SimpleGenericRecord<_, _>)
对于较长的情况,你可以写一个别名类型来简化事情
type Alias<'T> = int -> System.Collections.Generic.Dictionary<int, 'T>
let record4 = {
t1 = (failwith "Intentionally failing" : Alias<string>)
}
注意,record4求值将立即引发异常,因为它没有延迟