Scala类型检查出现lambda错误,而不是显式函数

6

我有以下Scala代码:

import java.util.{Comparator, function}

object ComparatorTest {
  Comparator.comparing[Int, String](new function.Function[Int, String] {
    override def apply(t: Int): String = t.toString
  })
}

这段代码没有问题。根据文档,我认为我应该能够用lambda表达式替换掉Function至少我是这样理解的,而且IntelliJ也是这个意见)。但是,当我替换它时,出现了问题。

  Comparator.comparing[Int, String]((t: Int) ⇒ t.toString)

我遇到了编译器错误:

Error:(6, 23) overloaded method value comparing with alternatives:
  (x$1: java.util.function.Function[_ >: Int, _ <: String])java.util.Comparator[Int] <and>
  (x$1: java.util.function.Function[_ >: Int, _ <: String],x$2: java.util.Comparator[_ >: String])java.util.Comparator[Int]
 cannot be applied to (Int => String)
  Comparator.comparing[Int, String]((t: Int) ⇒ t.toString)

我认为第一个选项应该匹配。 我刚刚提出了一个类似的问题,解决方案是显式指定类型参数,但在这种情况下,我认为我已经指定了我可以指定的所有内容。是否有另一种方法来使用lambda,或者需要显式的Function?如果是后者,是否有文档解释何时可以将lambda替换为SAM?
2个回答

5
TL;DR: 使用Ordering而不是直接使用Comparator
您可以使用类型注释将其强制识别为java.util.function.Function[Int, String]
Comparator.comparing[Int, String]((_.toString) : function.Function[Int, String])

请注意,_.toString周围的括号是必需的;否则,它会尝试将归属应用于lambda表达式中的表达式而不是整个lambda。这段代码基本上等同于:
val tmp: function.Function[Int, String] = _.toString
Comparator.comparing[Int, String](tmp)

然而,在编写Scala代码时,通常更好地使用Ordering。由于Ordering扩展自Comparator,因此它可以在任何需要Comparator的地方使用。你可以像这样使用它:
val cmp: Comparator[Int] = Ordering.by(_.toString)

或者:

val cmp = Ordering.by[Int, String](_.toString)

正如您所看到的,类型推断在这里工作得更好。

谢谢!是的,我有时使用“Comparators”的原因是它们具有“thenCompare”方法,我发现用于构建它们非常有用,并且与“Orderings”不兼容。Scala 2.13将为Orderings提供此功能,但谁知道它何时会发布:p - zale
@zale 同时,您可以使用元组来构建这样的排序,例如 Ordering.by(user => (user.lastName, user.firstName)) 用于 Ordering.by(_.lastName).orElseBy(_.firstName)(尽管我承认它不太易读)。 - Brian McCutchon

1
如果使用Comparator而不是Ordering的原因是thenCompare,那么可以轻松地通过隐式实现来解决:
object PimpOrdering {
  implicit class OrderOrElse[T](val o: Ordering[T]) extends AnyVal {
   def orElse(o2: Ordering[T]) = new Ordering[T] {
     def compare(a: T, b: T) = {
        val cmp = o.compare(a,b)
        if (cmp == 0) o2.compare(a,b) else cmp
     }
   }
   def orElse[S : Ordering](f: T => S) = orElse(Ordering.by(f))
 }
}

现在你可以写类似于

这样的内容。
Ordering.by[Foo, String](_.foo).orElse(_.bar).orElse(_.baz)

etc


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接