Syntax scala将多个函数调用参数合并成一个元组——可以禁用吗?

Syntax scala将多个函数调用参数合并成一个元组——可以禁用吗?,syntax,scala,tuples,tuple-packing,Syntax,Scala,Tuples,Tuple Packing,在我的项目中,这是一个很麻烦的违反类型安全性的行为,所以我正在寻找一种方法来禁用它。如果函数采用AnyRef(或java.lang.Object),则可以使用任何参数组合调用该函数,Scala将把参数合并成一个元组对象并调用该函数 在我的例子中,函数不需要元组,并且在运行时失败。我希望这种情况会在编译时被发现 object WhyTuple { def main(args: Array[String]): Unit = { fooIt("foo", "bar") } def fooIt

在我的项目中,这是一个很麻烦的违反类型安全性的行为,所以我正在寻找一种方法来禁用它。如果函数采用AnyRef(或java.lang.Object),则可以使用任何参数组合调用该函数,Scala将把参数合并成一个元组对象并调用该函数

在我的例子中,函数不需要元组,并且在运行时失败。我希望这种情况会在编译时被发现

object WhyTuple {
 def main(args: Array[String]): Unit = {
  fooIt("foo", "bar")
 }
 def fooIt(o: AnyRef) {
  println(o.toString)
 }
}
输出:

(foo,bar)

编译器能够解释没有圆括号的方法。因此,fooIt中的圆括号表示Tuple。您的呼叫与以下内容相同:

fooIt( ("foo","bar") )
也就是说,如果您使用诸如some(AnyRef)或Tuple1(AnyRef)之类的包装器,您可以使方法排除调用,并检索值。

我认为Predef中(x,y)的定义是负责的。“-Yno predefs”编译器标志可能会有一些用处,前提是您愿意手动导入其他需要的任何隐式。我的意思是,你必须到处添加import scala.Predef.。

编辑:据比我更了解情况的人说,以下答案实际上是错误的:请参阅。谢谢你指出这一点

这实际上是解析器的一个怪癖,而不是类型系统或编译器的怪癖。Scala允许在没有括号的情况下调用零或一个参数函数,但不允许调用具有多个参数的函数。因此,您编写的不是一个具有两个参数的调用,而是一个具有一个元组值参数的调用。但是,如果该方法确实包含两个参数,则调用将是两个参数的调用。代码的含义似乎会影响它的解析方式(这有点糟糕)


至于你能为此做些什么,那是很棘手的。如果这个方法确实需要两个参数,那么这个问题就会消失(也就是说,如果有人错误地试图用一个参数或三个参数调用它,他们会像您所期望的那样得到一个编译错误)。不要假设有一些额外的参数您一直推迟添加到该方法?:)

像这样的事情怎么样:

object Qx2 {
    @deprecated def callingWithATupleProducesAWarning(a: Product) = 2
    def callingWithATupleProducesAWarning(a: Any) = 3
}

元组具有产品特性,因此任何调用调用传递元组的TupleProduceSaWarning都会产生一个弃用警告。

这里根本没有隐式或Predef——只是老式的编译器魔术。你可以在地图上找到它。我现在无法在规范中找到它

如果您有足够的动力,可以向编译器添加一个-X选项来防止这种情况


或者,您可以避免编写接受超类型
TupleN

的arity-1方法。您还可以添加一个双参数覆盖,这将阻止编译器应用语法糖吗?通过使类型适当模糊,你不太可能得到误报。例如:

object WhyTuple {

  ...

  class DummyType

  def fooIt(a: DummyType, b: DummyType) {
    throw new UnsupportedOperationException("Dummy function - should not be called")
  }
}

如果一个函数接受一个
AnyRef
作为参数,它希望参数是任何东西,不是吗?我的意思是,即使scala没有自动将参数打包到一个元组中,您仍然能够显式地传递一个元组,这当然是完全类型安全的,因为您的函数接受任何东西,元组就是任何东西。如果您的函数只能处理某些类型的参数,那么应该声明它只接受这些类型的参数,或者动态检查参数类型。那么它期望什么呢?你可能得把它分解成不同的专家。当然,如果你期望的不是Tuple,那就没什么帮助了。。。但通常情况下(在其他编程语言中)约定是,如果函数需要1个参数,并使用2调用,则编译将失败。隐式函数会这样做吗?是否可以避免使用AnyRef?你把Scala类型系统扔进了窗口:它可能会受到一些性能的惩罚,但是你是否考虑过使用结构类型?除非我丢失了一些东西,这不是一个答案,而是对问题的前提的总结。FIY,如果你给调用添加更多的参数,你只会得到更高层次的元组:FooIT(Foo),“Bar”。,“jam”)产生Tuple3。{评论调用,而不是方法签名}不幸的是,这个答案最终获得了最多的投票(在发布此帖子时)。这实际上是不正确的——请看,而且很可爱,但是他可能会合法地想要将
Product
(想想任何case类)类型的值传递给该方法。我认为,如果您需要在正常使用中传递产品,您必须为所有要保护的元组类型添加n个单独的方法。当然,如果您有许多这样的方法,或者如果您需要为2个以上的参数执行此操作,那么这是不可伸缩的。