Как вы вызываете Function1 [_, String] в Scala? - PullRequest
3 голосов
/ 06 января 2011

Я ответил на вопрос о карте функций в Определение карты из строки в функцию в 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?

Ответы [ 2 ]

3 голосов
/ 06 января 2011
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
1 голос
/ 06 января 2011

Я бы сказал, что если вы приведете объект типа String к Any, если вы хотите использовать метод, определенный в String, вы должны привести его обратно к String.

Вы приводите функцию как функцию, которая принимает аргумент экзистенциального типа (что означает _ в контексте типа), поэтому вы не можете использовать ее как функцию, которая принимает Int. Чтобы использовать его как функцию, которая берет 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, который можно использовать, чтобы обойти стирание типа в случаях, подобных приведенному выше [но на самом деле это не так, как описано выше, потому что это немного небрежно]).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...