使用泛型类型复制和更新记录表达式

时间:2017-11-14 16:20:53

标签: f# c#-to-f#

我有两种类型,它们共享一个命名值。

type Type1 = 
    {
        p1: int;
        p2: int;
    } 
type Type2 = 
    {
        p1 : int;
        p3 : int;
    }

是否可以创建仅更改此命名值(p1)并返回新记录的函数?

我试过这么远:

type IType = 
    abstract member p1: int;

type Type1 = 
    {
        p1: int;
        p2: int;
    } 
    interface IType with
        member this.p1 = this.p1

type Type2 = 
    {
        p1 : int;
        p3 : int;
    }
    interface IType with
        member this.p1 = this.p1

let changeP1ToTen (value: 'a when 'a :> IType) = 
    let newValue = {value with p1 = 10}
    newValue

let type1 = 
    {
        p1 = 50
        p2 = 80
    }
let newType1 = 
    changeP1ToTen(type1)

这不起作用,因为编译器假定{value with p1 = 10}是Type2,它可能是。

如果有更好更聪明的解决方案,那也会有所帮助。

我知道如果我对我的类型使用mutable或者使用类而不是简单的记录,这是可能的,但我想知道是否有更好的方法来处理它而不是OO方法。

1 个答案:

答案 0 :(得分:0)

我的意思是,你可以试试这个......

type Type1 =
    {
        p1 : int;
        p2 : int;
    }
type Type2 =
    {
        p1 : int;
        p2 : int;
    }
type Wrapper =
    | TOne of Type1
    | TTwo of Type2

let changeP1ToTen = function
    | TOne of t1 -> { t1 with p1 = 10 }
    | TTwo of t2 -> { t2 with p1 = 10 }

let type1 = { p1 = 50; p2 = 80 }

// Requires extra wrapping step, is that a dealbreaker?
let newtype1 = TOne type1 |> changeP1ToTen

// If that's a problem for ya, here's a function to fix it
let iTypeToWrapper (value: 'a when 'a :> IType) =
    match value with
        | :? Type1 as t1 -> TOne t1
        | :? Type2 as t2 -> TTwo t2

let othernewtype1 = iTypeToWrapper type1 |> changeP1ToTen

iTypeToWrapper功能的问题在于,如果您传递的内容不是Type1Type2,则会失败。要解决此问题,如果您的用例可以使用选项,则可以使用以下内容。

// val iTypeToWrapper : ('a when 'a :> IType) -> Wrapper option
let iTypeToWrapper (value: 'a when 'a :> IType) =
    match value with
        | :? Type1 as t1 -> TOne t1 |> Some
        | :? Type2 as t2 -> TTwo t2 |> Some
        | _ -> None