scala - 高阶函数将类型 T 更改为类型 Nothing
scala - higher order functions change type T to type Nothing
排除环境问题:sbt console (Scala 2.11.8) & spark-shell (Spark 2.3, Scala 2.11)
我有一个视图绑定类型为 T 的高阶函数...但是当部分应用该函数时,arg t: T
类型签名从 T <% Double
变为 Nothing
.
用于演示的玩具示例:
// 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
.
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: T => Double)Double
def f1[T <% Double]: ((T, Int) => Double) = func[T](true)_
// f1: [T](implicit evidence: T => Double)(T, Int) => Double
f1[Double](10.0, 1)
<console>:41: error: too many arguments for method f1: (implicit evidence: Double => Double)(Double, Int) => Double
f1[Double](10.0, 1)
When I try to partially apply isValid
, I'd expect the result to be type (T, Int) => Double
值不能通用。因此对于某些特定的 T
,它可以具有这种类型,但您没有准确提供允许推断它的参数。您可以指定例如
val f1 = func[TheTypeYouWant](true) _
或
val f1: (TheTypeYouWant, Int) => Double = func(true) _
如果你希望它是通用的,它必须再次是 def
:
def f1[T <% Double] = func[T](true) _
排除环境问题:sbt console (Scala 2.11.8) & spark-shell (Spark 2.3, Scala 2.11)
我有一个视图绑定类型为 T 的高阶函数...但是当部分应用该函数时,arg t: T
类型签名从 T <% Double
变为 Nothing
.
用于演示的玩具示例:
// 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
.
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: T => Double)Double
def f1[T <% Double]: ((T, Int) => Double) = func[T](true)_
// f1: [T](implicit evidence: T => Double)(T, Int) => Double
f1[Double](10.0, 1)
<console>:41: error: too many arguments for method f1: (implicit evidence: Double => Double)(Double, Int) => Double
f1[Double](10.0, 1)
When I try to partially apply
isValid
, I'd expect the result to be type(T, Int) => Double
值不能通用。因此对于某些特定的 T
,它可以具有这种类型,但您没有准确提供允许推断它的参数。您可以指定例如
val f1 = func[TheTypeYouWant](true) _
或
val f1: (TheTypeYouWant, Int) => Double = func(true) _
如果你希望它是通用的,它必须再次是 def
:
def f1[T <% Double] = func[T](true) _