如何在 Scala 中匹配函数签名而不收到类型擦除编译器警告

发布于 2024-08-19 06:25:52 字数 1017 浏览 13 评论 0原文

任何人都可以重新编写此代码来执行相同的操作,但没有任何编译器警告吗?请:-

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

再次感

谢基思

Can anyone re-write this code to do the same thing but without any compiler warnings please:-

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")
    }

  }
}

Thousand thankyous

Keith

Update!!!!. Sorry making a real hash of this. Its my first question on SO

Just to let the gurus know I have tried something along the lines of this also to no avail:- (Can't compile it)

object TestTypeErasure {  

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

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

}  

I get error :-

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

Thanks again

Keith

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

酒几许 2024-08-26 06:25:53

您可以使用清单捕获类型信息。 (为了简单起见,这里 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)
}

You can capture the type information with Manifests. (T, R are invariant here to keep things simple.)

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 

For Scala 2.8 one can use context bounds, removing the two implicit parameters:

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)
}
2024-08-26 06:25:53

有多种方法可能有效,但没有一种方法那么简单。

一种选择是使用清单,但您必须定义自己的清单感知匹配变体。您可以阅读有关清单的更多信息 此处。如果您必须经常做此类事情,那么这将是一个不错的选择,尽管此功能仍被认为是实验性的。

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

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 包装器,它仍然会有点笨重(而且性能不高)。

(编辑以添加我丢失的清单链接。)

There are a variety of approaches that might work, none of which are all that straightforward.

One option is to use manifests, but you'd have to define your own variant of match that was manifest-aware. You can read more about manifests here. If you have to do this sort of thing a lot, that would be the way to go, although this feature is still considered to be experimental.

Another option, if your usage is relatively lightweight, is to wrap the function in some class that is not generic. For example,

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)

If you are wrapping several different functions, but not too many of them, you can create a base class WrappedFunction and then have things like AnyImpliesBoolean extend WrappedFunction.

Yet another option is to not actually pass functions around, but to instead use reflection to pass java.lang.Methods around. Methods know their types. Even with some pretty Scala wrappers, it still would be a little clunky (and it's not high-performance).

(Edited to add the manifest link I was missing.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文