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

Des*_*ino 6 f# c#-to-f#

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

type Type1 = 
    {
        p1: int;
        p2: int;
    } 
type Type2 = 
    {
        p1 : int;
        p3 : int;
    }
Run Code Online (Sandbox Code Playgroud)

是否可以创建仅更改此命名值(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)
Run Code Online (Sandbox Code Playgroud)

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

如果有一个更好,更聪明的解决方案,它也会有所帮助.

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

Dev*_*nch 1

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

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
Run Code Online (Sandbox Code Playgroud)

iTypeToWrapper 函数的问题是,如果您传入 aType1或 之外的其他内容,它将失败Type2。要解决此问题,如果您的用例可以接受使用选项,则可以使用以下内容。

// 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
Run Code Online (Sandbox Code Playgroud)