返回类型

时间:2017-07-13 13:25:17

标签: types f# constraints

假设我有以下类型:

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返回不同的类型(即PersonDataHighPersonDataLow),我必须编写两个不同的函数。

另一种方法是使用区分联合(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。

感谢。

1 个答案:

答案 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函数。