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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scala - 高阶函数将类型T更改为Nothing相关的知识,希望对你有一定的参考价值。

故障排除环境:sbt控制台(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 doc ...我看到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)
答案

当我尝试部分应用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) _

以上是关于scala - 高阶函数将类型T更改为Nothing的主要内容,如果未能解决你的问题,请参考以下文章

Scala高阶

scala高阶函数

2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法

Spark基础-scala学习

Scala类型系统——高级类类型(higher-kinded types)

Scala基础高阶函数隐式转换AKKA编程