在编译时强制执行scala varargs的非空

Nic*_*udo 5 scala

我有一个函数,需要相同类型的可变数量的参数,这听起来像varargs的教科书用例:

def myFunc[A](as: A*) = ???
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是myFunc无法接受空参数列表.在运行时有一种简单的方法可以强制执行:

def myFunc[A](as: A*) = {
  require(as.nonEmpty)
  ???
}
Run Code Online (Sandbox Code Playgroud)

问题在于它发生在运行时,而不是编译时.我希望编译器拒绝myFunc().

一种可能的解决方案是:

def myFunc[A](head: A, tail: A*) = ???
Run Code Online (Sandbox Code Playgroud)

这在myFunc使用内联参数调用时有效,但我希望我的库的用户能够传入一个List[A],这种语法非常笨拙.

我可以尝试两者兼得:

def myFunc[A](head: A, tail: A*) = myFunc(head +: tail)
def myFunc[A](as: A*) = ???
Run Code Online (Sandbox Code Playgroud)

但是我们回到了我们开始的地方:现在有一种myFunc使用空参数列表调用的方法.

我知道scalaz NonEmptyList,但是尽可能地,我想继续使用stlib类型.

有没有办法通过标准库来实现我的想法,或者我是否需要接受一些运行时错误处理,以获得真正感觉编译器应该能够处理的内容?

Joe*_*las 6

这样的事情怎么样?

scala> :paste
// Entering paste mode (ctrl-D to finish)

def myFunc()(implicit ev: Nothing) = ???
def myFunc[A](as: A*) = println(as)

// Exiting paste mode, now interpreting.

myFunc: ()(implicit ev: Nothing)Nothing <and> [A](as: A*)Unit
myFunc: ()(implicit ev: Nothing)Nothing <and> [A](as: A*)Unit

scala> myFunc(3)
WrappedArray(3)

scala> myFunc(List(3): _*)
List(3)

scala> myFunc()
<console>:13: error: could not find implicit value for parameter ev: Nothing
       myFunc()
             ^

scala> 
Run Code Online (Sandbox Code Playgroud)

用具有适当implicitNotFound注释的类替换Nothing 应该允许合理的错误消息.

  • @YuvalItzchakov但你仍然可以使用它像这样的'myFunc(List():_*)`.. OP不喜欢/想要 (3认同)

pam*_*amu 2

使用scala.collection.immutable.::

::是列表的缺点

在标准库中定义

::[A](head: A, tail: List[A])
Run Code Online (Sandbox Code Playgroud)

用于::定义myFunc

def myFunc[A](list: ::[A]): Int = 1

def myFunc[A](head: A, tail: A*): Int = myFunc(::(head, tail.toList))
Run Code Online (Sandbox Code Playgroud)

Scala REPL

scala> def myFunc[A](list: ::[A]): Int = 1
myFunc: [A](list: scala.collection.immutable.::[A])Int

scala> def myFunc[A](head: A, tail: A*): Int = myFunc(::(head, tail.toList))
myFunc: [A](head: A, tail: A*)Int
Run Code Online (Sandbox Code Playgroud)

  • @NicolasRinaudo 我没有看到任何其他方法可以做到这一点。不可能允许用户发送 List 作为输入并在编译时强制列表非空。好处是你不需要使用外部库 (2认同)