【问题标题】:Passing function with Subclass as argument to function which takes any function with Super class as parameter将带有子类的函数作为参数传递给函数,该函数将任何带有超类的函数作为参数
【发布时间】:2016-12-30 08:35:28
【问题描述】:

我有以下 scala 代码。

trait Super
case class Sub(value:String) extends Super
case class YetAnotherSub(value:String) extends Super
case class OnlyErrorType(value:String) extends Super

def function1[I <: Super, R](mapper : (I) => R, input: Super) (default: R): R = input match {
  case error: OnlyErrorType => 
    default

  case success: I => mapper(success)  // Ideally success => mapper(success)

  case _ => default // I don't want this line at all, as I'm not expecting any other type
}

def function2(input:String):Super = if(input.size >= 3) Sub("Greater") else OnlyErrorType("Lesser")

def function3(input:String):String = {
  val result = function2(input)
  function1({sub:Sub => sub.value.toUpperCase}, result) ("Empty Result")
}

function3("Input")

有许多类似于function2 的函数,它们接受一些参数并返回Super 的任何子类型。我想要一个通用映射器,比如function1,将类型Super 映射到其他类型,但在OnlyErrorType 的情况下返回默认值

换句话说,我想对OnlyErrorType 进行一些默认处理,但让调用函数(在本例中为function3)指定 SuccessType 的映射(Super 的任何子类型,OnlyErrorType 除外)。

我如何做到这一点?

上面的代码可以编译,但是我讨厌看到警告,

warning: abstract type pattern I is unchecked since it is eliminated by erasure

我认为必须有更好的方法来做到这一点。

【问题讨论】:

    标签: scala types pattern-matching


    【解决方案1】:

    你不喜欢这个警告很好;在这种情况下,它基本上意味着测试不起作用。

    最简单的方法是明确SuccessType

    sealed trait Super
    trait SuccessType extends Super
    case class Sub(value:String) extends SuccessType
    case class YetAnotherSub(value:String) extends SuccessType
    case class OnlyErrorType(value:String) extends Super
    
    def function1[R](mapper: SuccessType => R, input: Super) (default: R): R = input match {
      case _: OnlyErrorType => default
      case success: SuccessType => mapper(success)
    }
    

    注意因为Super是密封的,它不能直接在别处扩展,但是它的一个子类型可以,所以你可以添加新的SuccessTypes。如果这不是我们所希望的,也可以创建 SuccessType sealed。 当然,在这种情况下,function1({case sub:Sub =&gt; sub.value.toUpperCase}, result) ("Empty Result") 如果传递了YetAnotherSub,它将失败。如果这不是您想要的,那么您需要静态区分“Super 如果成功则为Sub”和“Super 如果成功则为YetAnotherSub”。你可以使用

    sealed trait Super[I <: Super[I]]
    case class Sub(value:String) extends Super[Sub]
    case class YetAnotherSub(value:String) extends Super[YetAnotherSub]
    case class OnlyErrorType[I <: Super[I]](value:String) extends Super[I]
    
    def function1[I <: Super[I], R](mapper : (I) => R, input: Super[I]) (default: R): R = input match {
      case error: OnlyErrorType[_] =>
        default
    
      case success => mapper(success.asInstanceOf[I])
    }
    
    def function2(input:String):Super[Sub] = if(input.size >= 3) Sub("Greater") else OnlyErrorType("Lesser")
    
    def function3(input:String):String = {
      val result = function2(input)
      function1({sub:Sub => sub.value.toUpperCase}, result) ("Empty Result")
    }
    
    function3("Input")
    

    但我不想这样做:function1 中的演员表实际上是安全的,但并非如此(并且错误地定义 Super 的新子类型可能会破坏它)。

    【讨论】:

    • 如果你的第一个建议可行,我会很高兴的。它无法编译。
    • 修正了建议。
    猜你喜欢
    • 1970-01-01
    • 2019-11-21
    • 1970-01-01
    • 2021-04-13
    • 2011-10-02
    • 1970-01-01
    • 2018-03-07
    • 2010-11-20
    相关资源
    最近更新 更多