【问题标题】:F# how to pass interface to a function?F#如何将接口传递给函数?
【发布时间】:2017-02-16 13:52:38
【问题描述】:

我有如下所示的操作数据:

type IHasShow =
  abstract member show:bool
type ShowHideNotCompletedData       = {show:bool}
type ShowHideCompletedData          = {show:bool}
[<Pojo>]
type ActionData =
  | ShowHideNotCompleted of ShowHideNotCompletedData
  | ShowHideCompleted of ShowHideCompletedData

稍后我尝试将 ShowHideNotCompletedData 或 ShowHideCompletedData 传递给函数,该函数只关心布尔“显示”成员,但无法弄清楚如何传递/转换它:

let setShowItem (data:IHasShow) negate item =
  if data.show && (negate item.completed) then
    { item with show = true}
  else if (negate item.completed) then
    { item with show = false}
  else
    item

但是如何调用这个函数呢?

let setShowFn = setShowItem (data :> IHasShow) not

错误:

Type constraint mismatch. The type 
    'ShowHideNotCompletedData'    
is not compatible with type
    'IHasShow'

试过

let setShowFn = setShowItem data not

错误:

The type 'ShowHideNotCompletedData' is not compatible with the type 'IHasShow'

除了使用 ShowHideNotCompletedData 和 ShowHideCompleted 复制粘贴 setShowItem 之外,还有其他方法吗?

如果有帮助的话;完整的源代码在这里:https://github.com/amsterdamharu/riot_redux_fable

最简单的解决方案是不传递数据而只传递布尔值:

let setShowItem show negate item =
  if (negate item.completed) then//simplified if statement
    { item with show = show}
  else
    item
//...

| ShowHideCompleted data ->
  let setShowFn = setShowItem data.show id
  { state with
      showCompleted = data.show
      items = state.items
      |> Array.map setShowFn}

我仍然想知道如何定义泛型类型并传递它。

【问题讨论】:

    标签: f#


    【解决方案1】:

    在您当前的解决方案中,您的两种类型 ShowHideNotCompletedDataShowHideCompletedData 是记录。它们具有接口的所有字段,但没有显式实现它们。解决方案是使接口显式:

    type ShowHideNotCompletedData(show) =
        interface IHasShow with
            member this.show = show
    type ShowHideCompletedData(show) = 
        interface IHasShow with
            member this.show = show
    

    实例化为ShowHideNotCompletedData true。对于替代解决方案,您可能需要咨询一些关于鸭子类型的 SO 问题,例如 this

    说了这么多:我有一种预感,您的数据类型定义有点过于复杂。 @robkuz 发布了一个没有界面的答案。就模块化和可测试性而言,您自己建议将 bool 传递给函数似乎更好。

    【讨论】:

      【解决方案2】:

      我必须承认:我不喜欢 F# 中的接口 - 一般不喜欢,但我认为从语法上讲它们是彻底的灾难。 所以我经常使用带有类型约束的内联函数。
      Achtung:使用这种代码可能会杀死十几只小狗或排序

      首先要摆脱你的接口和它的实现(反正你已经忘记了;-))

      type ShowHideNotCompletedData       = {show:bool}
      type ShowHideCompletedData          = {show:bool}
      type ActionData =
          | ShowHideNotCompleted of ShowHideNotCompletedData
          | ShowHideCompleted of ShowHideCompletedData
      

      然后写那个看起来很疯狂的函数

      let inline show< ^T when ^T : (member show : bool)> (x:^T) = 
            (^T : (member show : bool)(x)) 
      

      并应用它

      let setShowItem data =
          match data with
          | ShowHideNotCompleted x -> show x
          | ShowHideCompleted x -> show x
      

      【讨论】:

      • 我和你一样讨厌界面。您的解决方案比接口更惯用。我不确定它是否是手头问题的最佳解决方案,数据类型似乎过于复杂,但 OP 没有提供太多上下文。
      • let inline show x = (^T : (member show : bool)(x)) 类型推断 FTW :-)
      猜你喜欢
      • 2019-04-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多