假设我有以下类型:
type AddressLow = {
FlatNo: int
PinCode: string
}
type AddressHigh = {
FlatNo: int
AreaName: string
PinCode: string
}
type PersonDataLow = {
id:int
name:string
address: AddressLow
}
type PersonDataHigh = { //same label names, different type for address
id:int
name:string
address: AddressHigh
}
以下两个函数是构建地址:
let GetAddressLow () =
{AddressLow.FlatNo = 10; PinCode = "5245"}
let GetAddressHigh () =
{AddressHigh.FlatNo = 10; AreaName = "Bel Air"; PinCode = "8225"}
以下函数是构建PersonData:
let GetPerson fGetAddress inputId inputName = //return type inferred as PersonDataHigh
{
id = inputId
name = inputName
address = fGetAddress()
}
let p1 = GetPerson GetAddressLow 4 "John Smith" //compile error
let p2 = GetPerson GetAddressHigh 6 "Will Smith" //works
对于上述函数,返回类型由F#推断为PersonDataHigh
。
因此,要为PersonData返回不同的类型(即PersonDataHigh
和PersonDataLow
),我必须编写两个不同的函数。
另一种方法是使用区分联合(DU)但涉及DU类型和DU类型的案例标识符之间的来回转换次数。
是否可以对返回类型使用约束,以便只编写一次函数?说,像这样:
let inline GetPerson (fGetAddress) (inputId) (inputName)
: ^T when ^T: (member id: int) and ^T: (member name: string) and (^T: (member address: AddressLow) or ^T: (member address: AddressHigh)) = //compile error
{
id = inputId
name = inputName
address = fGetAddress()
}
如果没有,在这里使用DU是最佳选择吗?我正在使用F#3.0。
感谢。
答案 0 :(得分:6)
您是否考虑过在单Address
类型中嵌套低或高?
由于大多数数据是在Address
这两种类型之间共享的,我不认为将它作为一个有区别的联合或两种不同的类型是最明智的选择。相反,只需将其中一个属性作为一个被拒绝的联合。
最简单的方法是将AreaName
设为option
。
type Address = {
FlatNo: int
AreaName : string option
PinCode: string
}
type PersonData = {
id:int
name:string
address: Address
}
然后你可以去:
let GetAddressLow () =
{FlatNo = 10; AreaName = None; PinCode = "5245"}
let GetAddressHigh () =
{FlatNo = 10; AreaName = Some "Bel Air"; PinCode = "8225"}
然后您不需要任何花哨的东西来创建GetPerson
函数。