gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 09:54:04 25 4
gpt4 key购买 nike

背景:

我正在尝试通过在 Scala 中动态创建/组合来自匿名函数的部分函数(case ...)来减少代码并提高 Akka 中的代码重用。

要创建这些部分函数,​​我需要访问函数的参数类型(使用类型参数 T),但不幸的是,这会受到类型删除的影响。

我发现使用 TypeTagTypeClass 可以解决这个问题,这很棒。但是,我不想一次将我的函数转换为部分函数,​​而是希望使用 .map() 批量执行此操作。

但是,这似乎失败了;当通过映射使用该函数时,似乎 T 突然变成了 Nothing,使我的函数功能失调(没有双关语意)。

TL;DR:我可以让 lst(0) 也给 String 吗?

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-curious,我的实际函数有问题,而不是上面的 check():

def caseFn[T](fn: T => Unit)(implicit ct: ClassTag[T]): Actor.Receive = {
case ct(msg: T) => {
fn(msg)
}
}

最佳答案

你可以通过改变让它工作

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

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

这是怎么回事?

map(check) 的情况下,Scala 执行所谓的 eta-expansion 将方法 (check) 转换为函数,参见 Scala Language Specification Version 2.9 的 6.26.5 :

6.26.5 Eta Expansion

Eta-expansion converts an expression of method type to an equivalent expression of function type. It proceeds in two steps. First, one identifies the maximal sub-expressions of e; let's say these are e_1,...,e_m. For each of these, one creates a fresh name x_i. Let e' be the expression resulting from replacing every maximal subexpression e_i in e by the corresponding fresh name x_i. Second, one creates a fresh name y_i for every argument type T_i of the method (i=1,...n). The result of eta-conversion is then:

{ 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-expansion 并且必须推断泛型方法的类型(在 eta-expansion 期间生成)检查。由于 Scala 中类型推断的限制,它将推断 Nothing 而不是 String,因此第一个版本不起作用,而第二个版本可以。

关于Scala 函数在列表中丢失变量类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32264871/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com