【问题标题】:Discriminated union member methods有区别的联合成员方法
【发布时间】:2015-01-24 00:11:33
【问题描述】:

我想定义一个可区分联合的所有成员共享的方法。目前我已经像这样实现了它,但它看起来真的很不雅 - 当然有更好的方法。有什么建议吗?

type A = 
   {AData:string}
   member this.SharedMethod (x:float) : int= ...
type B =
   {BData:float}
   member this.SharedMethod (x:float) : int= ...
type AB =
| A of A
| B of B

let CallSharedMethod (ab:AB) x =
   match ab with
   | AB.A(a') -> a'.SharedMethod x
   | AB.B(b') -> b'.SharedMethod x

【问题讨论】:

  • 您缺少实例绑定,即:this.SharedMethod,否则将无法正常工作。此外,您还需要添加更多关于您的共享方法与 DU 实例(实际上是记录类型)有何作用的信息,因为如果它什么都不做,您可以使用常规函数。我确定不是你的情况。
  • 在我看来这种方法应该在 DU 上。但如果没有,你可以使用记录来实现一个接口。
  • 是的,很抱歉我的代码在语法上并不完全正确。我对模式更感兴趣——我如何表示 DU 的每个子类型共享一个通用方法名称这一事实?我将编辑代码以使其更正确。
  • 好的,我可以把CallSharedMethod设为AB的方法。但我仍然需要进行模式匹配。您的其他建议 - 将记录作为界面似乎是最好的选择。我会试试这个。
  • 如果您希望每个 DU 案例都表现相同,您就没有歧视。 :)

标签: inheritance f# discriminated-union


【解决方案1】:

这样的事情呢?

type AB =
    | A of string
    | B of float

    member self.SharedMethod (x : float) =
        match self with
        | A s -> x
        | B f -> f + x

这假设您希望 sum 类型的每个变体(也称为可区分联合)对 float 参数执行不同的操作。

对于A 的情况,我只返回原始值,因为我无能为力(因为stringfloat 之间没有通常有用的关系会产生float)。

【讨论】:

    【解决方案2】:

    在您的示例中,您 augmented record 类型 AB 每个都有一个实例成员。但是,您不仅可以增加记录类型,还可以增加 union 类型(如@Rodrick 的回答所示)。如果您这样做,工会的增强将由每个 DU 案例“共享”,这就是您所要求的。为了使这一点更明确,我已重命名您示例的某些部分:

    type A = { AData:string }
    type B = { BData:float }
    
    type AB =
        | ACase of A
        | BCase of B
        member __.SharedMethod x = 0
    
    let callSharedMethod (ab:AB) x = ab.SharedMethod x
    

    如果您在对象浏览器(或类似 ILSpy 的反编译器)中查看编译后的代码,您会看到 AB 被编译为两个子类 AB.ACaseAB.BCaseSharedMethod 的基类属于基类AB

    另请参阅F# 3.0 specification 的第 8.5.1 节:联合类型中的成员。

    【讨论】:

      猜你喜欢
      • 2018-06-27
      • 2021-02-14
      • 2018-11-24
      • 1970-01-01
      • 2019-06-28
      • 1970-01-01
      • 1970-01-01
      • 2014-12-21
      • 2022-01-08
      相关资源
      最近更新 更多