Scala类型推断不适用于通用案例类和lambda

时间:2016-06-03 02:02:24

标签: scala generics types lambda

我正在尝试应用函数:A => B到结果[A]得到一个结果[B]并得到一个奇怪的类型错误。

\1

我不确定如何解决此问题。看起来scala试图将函数的输出转换为字符串(可序列化),因为它无法在成功/失败和结果之间找到转换?

简化代码如下。我尝试附加显式类型信息,代码无法编译。任何帮助将不胜感激!

\1+

2 个答案:

答案 0 :(得分:3)

要解释原始问题:您没有指定Result.map的返回类型,因此Scala必须推断它。为此,它会查看两个分支。第一个的返回类型是Success[B]。第二个的返回类型是Failure[Nothing],因为Scala没有理由认为你的意思是Failure[B](m)

所以现在必须找到Success[B]Failure[Nothing]都适合的类型(他们的最小上限)。好吧,它们都扩展ProductSerializable(因为它们是案例类)。它们也都扩展Result,但具有不同的类型参数。 NothingB的最小上限为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]()

相关问题