我正在尝试应用函数:A => B到结果[A]得到一个结果[B]并得到一个奇怪的类型错误。
\1
我不确定如何解决此问题。看起来scala试图将函数的输出转换为字符串(可序列化),因为它无法在成功/失败和结果之间找到转换?
简化代码如下。我尝试附加显式类型信息,代码无法编译。任何帮助将不胜感激!
\1+
答案 0 :(得分:3)
要解释原始问题:您没有指定Result.map
的返回类型,因此Scala必须推断它。为此,它会查看两个分支。第一个的返回类型是Success[B]
。第二个的返回类型是Failure[Nothing]
,因为Scala没有理由认为你的意思是Failure[B](m)
!
所以现在必须找到Success[B]
和Failure[Nothing]
都适合的类型(他们的最小上限)。好吧,它们都扩展Product
和Serializable
(因为它们是案例类)。它们也都扩展Result
,但具有不同的类型参数。 Nothing
和B
的最小上限为B
,因此它们都延伸Result[_ <: B]
。这就是您map
Product with Serializable with Result[_ <: B]
的最终类型:Product with Serializable with Result[B]
。
请注意,通过应用Andy Hayden的回答,您将获得Result[B]
, not Result
这可能是您想要的。要做到这一点,要么明确指定返回类型(即使没有协方差也可以工作,希望你现在可以看到原因),或者使Product with Serializable
扩展{
test : {
server : {
ip : {
value : "1.2.3.4",
port : [
{
value : "80",
state : {
value : "open"
}
},
{
value : "443",
state : {
value : "open"
}
}
]
}
name : {
value : "test"
}
}
。
答案 1 :(得分:1)
正如Alexey所指出的,您应该指定Result的映射的返回类型(否则,失败类型是不明确的,尽管您可以指定失败类型而不是Failure[B]
):
sealed trait Result[A]{
// specify the return type Result[B]
def map[B](f: A => B): Result[B] = this match{
case Success((a, rest)) => Success((f(a), rest))
case Failure(m) => Failure(m) // alternatively use Failure[B](m) here
}
}
case class Success[A](result: (A, List[Char])) extends Result[A]
case class Failure[A](message: String) extends Result[A]
object Utils{
def map[A,B](r: Result[A], f: A => B):Result[B] = {
r.map(f)
}
}
这将使失败的类型正确:
scala> val f = Failure[Int]("oops")
Failure("oops"): Failure[Int]
scala> Utils.map(f, {i: Int => 4})
Failure("oops"): Result[Int]
vs(使用下面的协变解决方案):
scala> Utils.map(f, {i: Int => 4})
Failure(oops): Product with Serializable with Result[_37] forSome { type _37 <: Int }
这不是你想要的!
最初我建议你让你的类型协变(+A
):
sealed trait Result[+A]{
def map[B](f: A => B) = this match{
case Success((a, rest)) => Success((f(a), rest))
case Failure(m) => Failure(m)
}
}
case class Success[A](result: (A, List[Char])) extends Result[A]
case class Failure[A](message: String) extends Result[A]
object Utils{
def map[A,B](r: Result[A], f: A => B):Result[B] = {
r.map(f)
}
}
有关详细讨论,请参阅this great blogpost。
引用部分帖子:
子类型关系 假设Orange类扩展了Fruit hold 如果声明了类
Box[A]
,那么A
可以加上+
或-
作为前缀。没有注释的A是不变的,即:
Box[Orange]
与Box[Fruit]
没有继承关系。+ A是协变的,即:
Box[Orange]
是Box[Fruit]
的子类型 允许var f: Box[Fruit] = new Box[Orange]()
。-A是逆变的,即:
Box[Fruit]
是Box[Orange]
的子类型 允许var f: Box[Orange] = new Box[Fruit]()
。