如何在 Scala 中调用 Function1[_, String]?

发布于 2024-10-10 20:43:42 字数 819 浏览 1 评论 0原文

我在 定义映射中回答了有关函数映射的问题String to Function in Scala 导致 Function1[_, String] 我相信就打字问题而言是正确的,但可能没用,因为我不知道如何调用这样的函数:

scala> def f(x: Int) = x.toString
f: (x: Int)java.lang.String

scala> f(8)
res0: java.lang.String = 8

scala> val g: Function1[_, String] = f _
g: Function1[_, String] = <function1>

scala> g(8)
<console>:8: error: type mismatch;
 found   : Int(8)
 required: _$1 where type _$1
       g(8)
         ^

scala> val h: Function1[Int, String] = g
<console>:7: error: type mismatch;
 found   : (_$1) => String where type _$1
 required: (Int) => String
       val h: Function1[Int, String] = g

有没有办法使用g

I answered a question about a map of functions in Defining a Map from String to Function in Scala which led to a Function1[_, String] which I believe is correct as far as the typing question but possibly useless because I don't know how to invoke such a function:

scala> def f(x: Int) = x.toString
f: (x: Int)java.lang.String

scala> f(8)
res0: java.lang.String = 8

scala> val g: Function1[_, String] = f _
g: Function1[_, String] = <function1>

scala> g(8)
<console>:8: error: type mismatch;
 found   : Int(8)
 required: _$1 where type _$1
       g(8)
         ^

scala> val h: Function1[Int, String] = g
<console>:7: error: type mismatch;
 found   : (_$1) => String where type _$1
 required: (Int) => String
       val h: Function1[Int, String] = g

Is there any way to use g?

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

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

发布评论

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

评论(2

舟遥客 2024-10-17 20:43:42
scala> g.asInstanceOf[Any => String](5)
res3: String = 5

它会起作用,因为所有函数都会擦除相同的内容:Function1[AnyRef, AnyRef]。当您将其指定为 Any 时,传递 AnyVal 将在调用时自动装箱(并且将在方法中自动取消装箱)。

但是,您必须传递正确的参数类型。不然的话...

scala> g.asInstanceOf[Any => String](true)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Integer
scala> g.asInstanceOf[Any => String](5)
res3: String = 5

It will work because all functions erase to the same thing: Function1[AnyRef, AnyRef]. When you specify it as Any, then passing an AnyVal will auto-box it on call (and it will be auto-unboxed at the method).

However, you do have to pass the correct parameter type. Or else...

scala> g.asInstanceOf[Any => String](true)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Integer
零度℉ 2024-10-17 20:43:42

我想说,如果您想使用 String 中定义的方法,就好像您已将 String 类型的对象强制转换为 Any您必须将其转换为 String

您将该函数转换为采用存在类型参数的函数(这就是类型上下文中 _ 的含义),因此您不能将其用作采用 的函数整数。要将其用作采用 Int 的函数,您必须将其强制转换回来。

当与集合或其他泛型类进行模式匹配时,也存在同样的问题:

def firstLength(collection: Any): Int ={
  collection match {
    // this is how you would have liked to write it
    // case list: List[String] => list.head.length
    // case map: Map[String, String] => map.values.head.length
    // but this is how you have to write it because of type erasure
    case list: List[_] => list.asInstanceOf[List[String]].head.length
    case map: Map[_, _] => map.asInstanceOf[Map[String, String]].values.head.length
  }
}

类型信息不存在,因此无法在 List[String] 上进行匹配,而必须在存在性上进行匹配输入 List[_] (你的说法可能是错误的,我认为这不是存在的泛型类型),然后进行强制转换。这或多或少正是您遇到的问题,您所追求的类型已被删除,并且无法将其恢复(除非您可以使用与可使用的 ClassManifest 相同的技巧在上面的情况下绕过类型擦除[但实际上不是上面的情况,因为它有点草率])。

I would say that it's like if you've cast an object of type String as Any, if you want to use a method defined in String you have to cast it back as a String.

You cast the function as a function that takes an argument of an existential type (which is what _ in a type context means), so you can't use it as a function that takes an Int. To use it as a function that takes an Int you have to cast it back.

The same problem exists when pattern matching with collections, or other generic classes:

def firstLength(collection: Any): Int ={
  collection match {
    // this is how you would have liked to write it
    // case list: List[String] => list.head.length
    // case map: Map[String, String] => map.values.head.length
    // but this is how you have to write it because of type erasure
    case list: List[_] => list.asInstanceOf[List[String]].head.length
    case map: Map[_, _] => map.asInstanceOf[Map[String, String]].values.head.length
  }
}

The type information isn't there, so you can't match on List[String], instead you have to match on the existential type List[_] (might be wrong on how you say that, it's not the generic type that is existential, I think) and then cast. This is more or less exactly the problem you have, the type you're after has been erased, and there's no way to get it back (unless you can use the same trick with ClassManifest that can be used to get around type erasure in cases like the one above [but not actually the case above, because it's a bit sloppy]).

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