Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala函数在列表中丢失变量类型?_Scala_Generics_Akka_Type Erasure - Fatal编程技术网

Scala函数在列表中丢失变量类型?

Scala函数在列表中丢失变量类型?,scala,generics,akka,type-erasure,Scala,Generics,Akka,Type Erasure,背景: 我试图通过从Scala中的匿名函数动态创建/组合部分函数(case…)来减少代码并提高Akka中的代码重用 要创建这些部分函数,我需要访问函数的参数类型(使用类型参数T),但不幸的是,这会被类型擦除 我发现使用TypeTags或TypeClasses我可以处理这个问题,这很好。但是,我希望使用.map()成批地将函数转换为部分函数,而不是一次转换一个函数 然而,这似乎是失败的;当通过映射使用函数时,它似乎突然变为Nothing,使我的函数功能失调(并非有意双关语) TL;DR:我可以让l

背景:

我试图通过从Scala中的匿名函数动态创建/组合部分函数(case…)来减少代码并提高Akka中的代码重用

要创建这些部分函数,我需要访问函数的参数类型(使用类型参数T),但不幸的是,这会被类型擦除

我发现使用
TypeTag
s或
TypeClass
es我可以处理这个问题,这很好。但是,我希望使用
.map()
成批地将函数转换为部分函数,而不是一次转换一个函数

然而,这似乎是失败的;当通过映射使用函数时,它似乎突然变为
Nothing
,使我的函数功能失调(并非有意双关语)

TL;DR:我可以让lst(0)也给出字符串吗

import scala.reflect.ClassTag
def fn = (s: String) => {}
def check[T](fn: T => Unit)(implicit ct: ClassTag[T]) = ct
check(fn)
//scala.reflect.ClassTag[String] = java.lang.String
val lst = List(fn).map(check)
lst(0)
//scala.reflect.ClassTag[Nothing] = Nothing
对于Akka好奇者来说,我的实际函数是有问题的,而不是上面的
check()


如果您这样做,效果会更好:

val lst = List(fn).map(check(_))
// lst: List[scala.reflect.ClassTag[String]] = List(java.lang.String)
不完全确定原因。

scala>检查_
scala> check _
res19: (Nothing => Unit) => scala.reflect.ClassTag[Nothing] = <function1>

scala> check(_: String => Unit)
res20: (String => Unit) => scala.reflect.ClassTag[String] = <function1>

scala> List(fn).map(check)
res21: List[scala.reflect.ClassTag[Nothing]] = List(Nothing)

scala> List(fn).map(check _)
res22: List[scala.reflect.ClassTag[Nothing]] = List(Nothing)

scala> List(fn).map(check(_))
res23: List[scala.reflect.ClassTag[String]] = List(java.lang.String)
res19:(Nothing=>Unit)=>scala.reflect.ClassTag[Nothing]= scala>check(ux:String=>Unit) res20:(String=>Unit)=>scala.reflect.ClassTag[String]= scala>列表(fn).map(检查) res21:List[scala.reflect.ClassTag[Nothing]]=List(Nothing) scala>列表(fn).map(选中) res22:List[scala.reflect.ClassTag[Nothing]]=List(Nothing) scala>列表(fn).map(勾选(33;)) res23:List[scala.reflect.ClassTag[String]]=List(java.lang.String)
您可以通过更改

val lst = List(fn).map(check)

这是怎么回事

map(check)
情况下,Scala进行所谓的
eta扩展
,以将方法(
check
)转换为函数,请参见第6.26.5节:

6.26.5 Eta扩展

Eta扩展将方法类型的表达式转换为函数类型的等效表达式。它分两步进行。首先,确定e的最大子表达式;假设这些是e_1,…,e_m。对于其中的每一个,我们都会创建一个新名称x_i。设e'是将e中的每个最大子表达式e_i替换为相应的新名称x_i而得到的表达式。其次,为方法的每个参数类型T_i(i=1,…n)创建一个新名称y_i。eta转换的结果是:

{ val x_1 = e_1;
  ...
  val x_m = em;
  (y_1: T_1,...,y_n:T_n) => e'(y_1,...,y_n)
}

因此,在
map(check)
中,Scala执行eta扩展,并且必须推断通用方法
check
的类型(在eta扩展期间生成)。由于Scala中类型推断的局限性,它将推断
而不是
字符串
,因此第一个版本不起作用,而第二个版本不起作用。

>不完全确定原因。=>eta扩展:),更多信息请参见我的答案
val lst = List(fn).map(check(_))
{ val x_1 = e_1;
  ...
  val x_m = em;
  (y_1: T_1,...,y_n:T_n) => e'(y_1,...,y_n)
}