У меня есть прецедент, когда мне дают Java-массив классов-оболочек, например, обертывание int, и я хочу преобразовать их в ValueSet из одних и тех же данных, но я столкнулся с загадочной проблемой с неявными преобразованиями. Вот пример Java и Scala, которые я пытаюсь сделать:
.../Java/demoapi/SomeWrapper.java
package demoapi;
public class SomeWrapper {
public static final int JavaOne = 1;
public static final int JavaTwo = 2;
public int m_theInt;
};
.../Scala/demo.scala
package demotest
import demoapi._
object TestEnum extends Enumeration {
val One, Two = Value
}
object SomeWrapperEx {
implicit def fromJava(in: Array[SomeWrapper]): TestEnum.ValueSet = {
in.map(x => fromInt(x.m_theInt))
}
def fromInt(in: Int): TestEnum.Value = {
in match {
case SomeWrapper.JavaOne => TestEnum.One
case SomeWrapper.JavaTwo => TestEnum.Two
}
}
}
Карта не может скомпилироваться со следующей ошибкой:
Error:(11, 27) value m_theInt is not a member of demotest.TestEnum.Value
in.map(x => fromInt(x.m_theInt))
^
Мой вопрос: как уже был преобразован тип элемента массива в TestEnum.Value? Мне приходилось работать, бросая подобные импликации, но я чувствую, что это должно работать как-то...
EDIT: Я уверен, что мне нужно сделать больше, чтобы заставить его работать, например, возможно преобразовать Array [TestEnum.Value] в ValueSet, но я пока не дошел до этого.
Вы ожидаете преобразовать свой массив в коллекцию (ArrayOps), чтобы вы могли работать с ней.
Но вы ожидаете создать ValueSet, и для этого машина нуждается в способе ее создания - CanBuildFrom.
Это подразумевалось здесь:
Поскольку вы предоставляете способ преобразования своего массива в ValueSet, он с радостью применит его, чтобы использовать CanBuildFrom для него.
-Xprint:typer
показывает вам направление, которое он принимает:
implicit def fromJava(in: Array[demoapi.SomeWrapper]): demoapi.TestEnum.ValueSet = SomeWrapperEx.this.fromJava(in).map[Nothing, demoapi.TestEnum.ValueSet](((x: demoapi.TestEnum.Value) => SomeWrapperEx.this.fromInt(x.<m_theInt: error>)))(demoapi.this.TestEnum.ValueSet.canBuildFrom);
У меня также возникают проблемы с работой с ValueSet как обычной коллекцией, так что теперь я этого не делаю.
Например, всегда начинайте с ValueSet:
$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_05).
Type in expressions to have them evaluated.
Type :help for more information.
scala> object Days extends Enumeration { val M,T,W,Th,F,Sa,S = Value }
defined object Days
scala> val ds = (2 to 5).toArray
ds: Array[Int] = Array(2, 3, 4, 5)
scala> Days.values filter (ds contains _.id)
res0: Days.ValueSet = Days.ValueSet(W, Th, F, Sa)
или построить вручную:
scala> Days.ValueSet.empty
res1: Days.ValueSet = Days.ValueSet()
scala> res1 + Days.T
res2: Days.ValueSet = Days.ValueSet(T)
все это CanBuildFrom делает так или иначе:
scala> implicit val xxx = new collection.generic.CanBuildFrom[Array[Int], Days.Value, Days.ValueSet] {
| def apply() = Days.ValueSet.newBuilder
| def apply(from: Array[Int]) = apply()
| }
xxx: scala.collection.generic.CanBuildFrom[Array[Int],Days.Value,Days.ValueSet] = $anon$1@6b474074
scala> (2 to 5) map (_ => Days.T)
res4: scala.collection.immutable.IndexedSeq[Days.Value] = Vector(T, T, T, T)
scala> (2 to 5) map (Days(_))
res5: scala.collection.immutable.IndexedSeq[Days.Value] = Vector(W, Th, F, Sa)