Scala 为什么对Unit和()类型的u(下划线)处理不同?

Scala 为什么对Unit和()类型的u(下划线)处理不同?,scala,Scala,我有一个返回Future[Unit]的方法,所以当我调用whenReady 这两个选项起作用:whenReady(doItAsync())({})和whenReady(doItAsync()){{{u=>} 但这不是:whenReady(doItAsync())(()=>{}) 不是\uu类型的Unit和空参数列表在这种情况下是等效的吗?虽然类型Unit类似于其他语言的void,但并不完全相同。 这个特别的问题来自Java(以及Scala)泛型实现中的一个限制:它们是使用。特别是它意味着泛型方法

我有一个返回
Future[Unit]
的方法,所以当我调用
whenReady

这两个选项起作用:
whenReady(doItAsync())({})
whenReady(doItAsync()){{{u=>}

但这不是:
whenReady(doItAsync())(()=>{})


不是
\uu
类型的
Unit
和空参数列表在这种情况下是等效的吗?

虽然类型
Unit
类似于其他语言的
void
,但并不完全相同。 这个特别的问题来自Java(以及Scala)泛型实现中的一个限制:它们是使用。特别是它意味着泛型方法不能改变参数的数量。现在,当类型参数为
Unit
时会发生什么?我们仍然必须有相同数量的参数,并且不能神奇地将返回类型更改为不返回任何内容(
void
),因为这将是一个不同的签名。因此,答案是使用一些只有伪值的伪类型:
scala.runtime.BoxedUnit
。因此,
Unit
可能表示您不需要但必须存在的实际参数。因此类型签名
()=>{}
与此不匹配,因为它不需要参数

还要注意,Java本身也存在同样的问题,因此有一个类似的东西叫做

更新

为了让这一点更清楚,考虑下面的泛型与非泛型代码:

def foo(f: () => String) = println(f())

def fooGeneric[T](arg: T, f: (T) => String) = println(f(arg))

foo(() => "Non-generic")
fooGeneric[Unit]((), (_) => "generic")

请注意,逻辑上
fooGeneric[Unit]
foo
相同,您仍然必须传递第一个参数和接受(无用)参数作为第二个参数的函数。

尽管type
Unit
与其他语言中的
void
类似,但并不完全相同。 这个特别的问题来自Java(以及Scala)泛型实现中的一个限制:它们是使用。特别是它意味着泛型方法不能改变参数的数量。现在,当类型参数为
Unit
时会发生什么?我们仍然必须有相同数量的参数,并且不能神奇地将返回类型更改为不返回任何内容(
void
),因为这将是一个不同的签名。因此,答案是使用一些只有伪值的伪类型:
scala.runtime.BoxedUnit
。因此,
Unit
可能表示您不需要但必须存在的实际参数。因此类型签名
()=>{}
与此不匹配,因为它不需要参数

还要注意,Java本身也存在同样的问题,因此有一个类似的东西叫做

更新

为了让这一点更清楚,考虑下面的泛型与非泛型代码:

def foo(f: () => String) = println(f())

def fooGeneric[T](arg: T, f: (T) => String) = println(f(arg))

foo(() => "Non-generic")
fooGeneric[Unit]((), (_) => "generic")
请注意,逻辑上
fooGeneric[Unit]
foo
相同,您仍然必须传递第一个参数和接受(无用)参数作为第二个参数的函数

在这种情况下,单位类型和空参数列表是否等效

否。
\u=>{}
定义了一个具有单个参数的函数(在本上下文中,该函数具有类型
单元
),
()=>{}
定义了一个没有参数的函数。它们的类型是
Unit=>Unit
()=>Unit
,或者没有语法糖
Function1[Unit,Unit]
Function0[Unit]
。这些类型实际上并不相关:它们都不是另一个的子类型

您可以使用模式匹配编写一个单参数匿名函数,使用
单元
()
{case()=>…}
。但这样做毫无意义

在这种情况下,单位类型和空参数列表是否等效

否。
\u=>{}
定义了一个具有单个参数的函数(在本上下文中,该函数具有类型
单元
),
()=>{}
定义了一个没有参数的函数。它们的类型是
Unit=>Unit
()=>Unit
,或者没有语法糖
Function1[Unit,Unit]
Function0[Unit]
。这些类型实际上并不相关:它们都不是另一个的子类型


您可以使用模式匹配编写一个单参数匿名函数,使用
单元
()
{case()=>…}
。但是这样做没有意义。

不,
\uu
表示任何类型的未使用参数。您得到了什么错误?@Bergi我得到了
类型不匹配,预期:Unit=>NotInferredU,实际:()=>Unit
不,
\u
表示任何类型的未使用参数。您得到了什么错误?@Bergi我得到了
类型不匹配,应为:Unit=>NotInferredU,actual:()=>Unit
,但类型是在编译时推断的。编译器只是不接受
()=>{}
作为
{}
的有效等价物。如果
的类型是
Unit
@PavelVoronin,我看不出Scala编译器在理论上不能将类型
函数0[String]
强制为
函数1[Unit,String]的原因
在这种特殊情况下,它不能做到这一点(可能很难始终如一地做到这一点)
当READY
第二个参数类型为
Function1[T,U]
时,在JVM级别上,这与
Function0[String]
非常不同,因此必须传递与
Function1
匹配的内容。如果
Future
whenReady
不是泛型的,则使用
()=>{}
的代码可以工作。代码不会编译,因为它们是泛型的。这就是C的工作原理:明确区分
void DoIt(Action act)
U DoIt(Func Func)
U DoIt(Func Func)
和void DoIt(Action act)`。所以我想说我喜欢这个泛化=)@PavelVoronin,类型擦除,尽管是一种实现d