【问题标题】:How can I match a function signature without getting type erasure compiler warnings in Scala如何匹配函数签名而不在 Scala 中获得类型擦除编译器警告
【发布时间】:2010-01-29 20:16:46
【问题描述】:

任何人都可以重写这段代码来做同样的事情,但没有任何编译器警告:-

object TestTypeErasure {

  def main(args:Array[String]) {

    def myFunction(myObject:Any):Boolean = {
      true
    }

    val myVariable: (Any => Boolean) = myFunction

    myVariable match {
      case function:(Any => Boolean) => println("Match")
    }

  }
}

万分感谢

基思

更新!!!!抱歉,对此进行了真正的散列。这是我关于 SO 的第一个问题

只是为了让大师知道我已经尝试过类似的方法也无济于事:-(无法编译)

object TestTypeErasure {  

    def doTest(parameter: Any) = {  
        parameter match {  
            case function:Function1[_, _] => function("Whatever")  
        }  
    }  

    def main(args:Array[String]) {  
    }  

}  

我得到错误:-

TestTypeErasure.scala:6: error: type mismatch;
  found   : java.lang.String("Whatever")
  required: _
    case function:Function1[_, _] => function("Whatever")
                                                ^
one error found

再次感谢

基思

【问题讨论】:

    标签: scala types pattern-matching compiler-warnings type-erasure


    【解决方案1】:

    您可以使用清单捕获类型信息。 (为了简单起见,T、R 在这里是不变的。)

    import scala.reflect._
    def matchFunction[T,R](f: Function1[T,R], t : T)(implicit mt : Manifest[T], mr : Manifest[R]) = {
      val result = if ((mt.erasure, mr.erasure) == (classOf[Any], classOf[Boolean]))  "any, boolean " + f(t)
      else if((mt.erasure, mr.erasure) == (classOf[Int], classOf[Int])) "int, int " + f(t)
      else "Unknown " + f(t)
      println(result)
    }
    
    scala>     matchFunction((x : Int) => x + 1, 1)
    int, int 2
    
    scala>     matchFunction((x : Any) => true, 1 : Any)
    any, boolean true
    
    scala>     matchFunction((x : Boolean) => ! x, false)
    Unknown 
    

    对于 Scala 2.8,可以使用上下文边界,删除两个隐式参数:

    import scala.reflect._
    def matchFunction[T: Manifest,R : Manifest](f: Function1[T,R], t : T) = {
      val mt = implicitly[Manifest[T]]
      val mr = implicitly[Manifest[T]]
      val result = if ((mt.erasure, mr.erasure) == (classOf[Any], classOf[Boolean]))  "any, boolean " + f(t)
      else if((mt.erasure, mr.erasure) == (classOf[Int], classOf[Int])) "int, int " + f(t)
      else "Unknown " + f(t)
      println(result)
    }
    

    【讨论】:

    • 请注意,为此您需要 Scala 2.8。
    • @retronym 不,这适用于 2.7.7。清单应该从 2.7.2 开始可用。
    【解决方案2】:

    【讨论】:

    • 您好,我已经看过了。我尝试了最佳答案。下一个困难是我想调用这个函数。如果我将代码更改为实际调用下面的函数,则会出现编译器错误。有谁知道我如何绕过这个对象 TestTypeErasure { def doTest(parameter: Any) = { parameter match { case function:Function1[_, _] => function("Whatever") } } def main(args:Array[ String]) { } } 再次感谢基思
    【解决方案3】:

    有多种方法可能奏效,但都不是那么简单。

    一种选择是使用清单,但您必须定义自己的可识别清单的匹配变体。您可以阅读更多关于清单here 的信息。如果您必须经常做这种事情,那将是可行的方法,尽管此功能仍被认为是实验性的。

    如果您的使用相对轻量级,另一种选择是将函数包装在某个非通用类中。例如,

    object Example {
      def hasString(a:Any) = (a!=null && a.toString.length>0)
    
      case class AnyImpliesBoolean(f: (Any) => Boolean) { } 
      implicit def callAIB(aib: AnyImpliesBoolean) = aib.f
    
      def callWrapped(a: Any) {
        a match {
          case aib: AnyImpliesBoolean => println( aib("Check") )
          case _ => println("(Nothing)")
        }
      }
    
      def tryMe() {
        val has = AnyImpliesBoolean(hasString _)
        callWrapped( has )
        callWrapped("foo")
        callWrapped((s:String)=>true)
      }
    }
    
    scala> Example.tryMe
    true
    (Nothing)
    (Nothing)
    

    如果您要包装几个不同的函数,但不是太多,您可以创建一个基类 WrappedFunction,然后让 AnyImpliesBoolean 之类的东西扩展 WrappedFunction。

    另一种选择是实际上不传递函数,而是使用反射来传递 java.lang.Methods。方法知道它们的类型。即使有一些漂亮的 Scala 包装器,它仍然会有点笨重(而且它不是高性能的)。

    (已编辑以添加我缺少的清单链接。)

    【讨论】:

      猜你喜欢
      • 2021-08-03
      • 1970-01-01
      • 1970-01-01
      • 2021-01-10
      • 2015-11-21
      • 1970-01-01
      • 1970-01-01
      • 2018-01-30
      • 2015-08-18
      相关资源
      最近更新 更多