scala-高阶函数将类型T更改为Nothing

时间:2019-02-06 22:17:14

标签: scala types polymorphism higher-order-functions

故障排除环境:sbt控制台(Scala 2.11.8)和spark-shell(Spark 2.3,Scala 2.11)

我有一个视图绑定类型T ...的高阶函数,但是当部分应用该函数时,arg t: T类型签名从T <% Double变为Nothing。 / p>

要演示的玩具示例:

// tot: T needs to work on (at least) Int, Long, Double, Float
// no common supertype -> some kind of context bound

def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int): Double = 
  if (isValid) tot.toDouble / cnt else Double.NaN

当我尝试部分应用isValid时,我希望结果为类型(T, Int) => Double,但类型最终以(Nothing, Int) => Double结尾,并且我无法传递arg tot。 / p>

val f1 = func(true)_   // f1: (Nothing, Int) => Double = <function2>
val f2 = func(false)_  // f2: (Nothing, Int) => Double = <function2>

val g1 = f1(10.0, 1)
// <console>:40: error: type mismatch;
// found   : Double(10.0)
// required: Nothing
//       val g1 = f1(10.0, 1)

在定义f1或f2时,我没有收到任何错误消息...因此很难解释。它将arg tot: T转换为类型Nothing

正在检查scala文档...我看到scala.Nothing是其他所有类型的子类型,所以我认为也许它失去了对T的了解...这可能与类型擦除有关...所以我尝试了使用ClassTag ...

import scala.reflect.ClassTag

def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int)(implicit tag: ClassTag[T]): Double = 
  if (isValid) tot.toDouble / cnt else Double.NaN

那没有帮助。同样的问题。

如果我尝试使用implicit num: Numeric[T],它将以一种新的方式阻塞类型Nothing ...

def func[T](isValid: Boolean)(tot: T, cnt: Int)( implicit num: Numeric[T] ): Double = 
  if (isValid) num.toDouble(tot) / cnt else Double.NaN

val f1 = func(true)_
// <console>:40: error: could not find implicit value for parameter num: Numeric[Nothing]
//        val f1 = func(true)_

如果我一次全部应用(在顶部使用第一个“ func”),则效果很好...

val g1 = func(true)(10.0, 1)
// g1: Double = 10.0

但是在我的真实(非玩具)代码中,这不是一个选择。

这里发生了什么?部分应用后如何使func工作?

编辑[@Alexey的解决方案]

我无法获得首选的“ def”方法。

def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int): Double =
  if (isValid) tot.toDouble / cnt else Double.NaN
// func: [T](isValid: Boolean)(tot: T, cnt: Int)(implicit evidence$1: T => Double)Double

def f1[T <% Double]: ((T, Int) => Double) = func[T](true)_
// f1: [T](implicit evidence$1: T => Double)(T, Int) => Double

f1[Double](10.0, 1)
<console>:41: error: too many arguments for method f1: (implicit evidence$1: Double => Double)(Double, Int) => Double
   f1[Double](10.0, 1)

1 个答案:

答案 0 :(得分:2)

  

当我尝试部分应用isValid时,我希望结果为(T, Int) => Double

值不能是通用的。因此,它可以为某些特定的T使用这种类型,但是您没有提供确切的参数来推断它。您可以指定例如

val f1 = func[TheTypeYouWant](true) _

val f1: (TheTypeYouWant, Int) => Double = func(true) _

如果您希望它是通用的,则必须再次为def

def f1[T <% Double] = func[T](true) _