使用Any *参数键入功能不匹配

时间:2015-02-27 15:56:02

标签: scala

我有这个方法:

private def getMachineResponse(computeFunc: (Any*) => Option[List[MyThing]], any: Any*):  Route = {
  get {
    val things = computeFunc(any)

    // now do some stuff 
  }
}

我想用两个不同的computeFunc作为参数来调用这个方法,一个有2个参数,另一个有4个参数。但是调用不会编译。我正在尝试这个:

getMachineResponse(computeKnownItems, 1, "s")

其中computeKnownItems如下:

private def computeKnownItems(mtype: Int, id: String): Option[List[MyThing]] = {
  // get the things
}

错误是“类型不匹配,找到(Int,String),必需(Any *)”。

有没有办法实现我正在尝试的,或者我应该为每种类型的computeFunc进行重载我需要传入? (如use(int,String)=>用于computeFunc的选项[List [MyThing]]然后创建一个带有computeFunc的重载:(int,int,int,String)=> ... etc)

谢谢。

稍后编辑:将参数名称更改为mtype(因为它在我的实际代码中,我在这里发布时太过美妙了!)

1 个答案:

答案 0 :(得分:0)

首先......我没有看到这个东西编译。除co-variancecontra-variance问题外,还有很多问题。

最明显的问题是:

private def computeKnownItems(type: Int, id: String): Option[List[MyThing]] = {
  // get the things
}

否...您无法使用type作为标识符... type是Scala中的关键字。

其他问题是,这样的事情无法编译:

def simple( func: ( Int* ) => Int, ints: Int* ): Int = func( ints )

error: type mismatch;
  found   : Seq[Int]
  required: Int
    def func( ints: Int* ): Int = func( ints )

这也不会:

def a( func: (Int*) => Int )( ints: Int* ): Int = func( ints )

error: type mismatch;
  found   : Seq[Int]
  required: Int
    def a( func: (Int*) => Int )( ints: Int* ): Int = func( ints )
                                                           ^

这也不会:

scala> def fund( ints: Int* ): Int = ints.toList.sum
fund: (ints: Int*)Int

scala> def func( ints: Int* ): Int = fund( ints )
<console>:34: error: type mismatch;
  found   : Seq[Int]
  required: Int
    def func( ints: Int* ): Int = fund( ints )
                                        ^

以上所有问题都是该函数期望多个Int参数,但是获得了一个参数,这是一个序列(*-parameters在函数体中被隐式接收为Seq )。传递可变大小参数的正确方法如下:

scala> def simple( func: ( Int* ) => Int, ints: Int* ): Int = func( ints: _* )
simple: (func: Int* => Int, ints: Int*)Int

_*是特殊的annotation,只能用于函数*-parameter的参数。它使任何序列作为*-parameter传递。

scala> val l = List( 4, 5, 6, 7, 3, 6, 3 )
l: List[Int] = List(4, 5, 6, 7, 3, 6, 3)    

scala> def pp( ints: Int* ) = println( ints )
pp: (ints: Int*)Unit

// All Int* is implicitly received as a Seq[ Int ]
// ( WrappedArray[ int ] in this case ) in function body.
scala> pp( 4, 5, 6 )
WrappedArray( 4, 5, 6 )

// Received as List[ Int ] in this case
scala> pp( l: _* )
List(4, 5, 6, 7, 3, 6, 3)

scala> def a( ints: Int* ) = ints.sum
a: (ints: Int*)Int

// passing a list wont work
scala> a( l )
<console>:11: error: type mismatch;
  found   : List[Int]
  required: Int
            a( l )
               ^

// list passed as multiple parameters
scala> a( l: _* )
res8: Int = 34

现在,遇到主要问题......似乎你没有考虑过两个被称为co-variancecontra-variance的概念。

虽然这些都是非常一般的概念......让我在参考typesclasses时解释这些概念。

可以说,我们有两种类型AnimalHorse,其中HorseAnimalHorse <: Animal的子类型。

现在,让我们考虑一个着名的类型 - List[ +T ]。现在为什么+签名......基本上+表示List[ T ] co-varianttype T,这意味着如果Horse <: Animal则{ {1}}。这反过来意味着您可以在需要List[ Horse ] <: List[ Animal ]实例的任何地方传递List[ Horse ]的实例。如果你考虑一下,即使是英语也是如此。

但是,如果您谈论功能,它们是List[ Animal ],请考虑contra-variant,这意味着如果Function1[ -T, +R ]Horse <: AnimalFunction1[ Animal, R ]的子类型或Function1[ Horse, R ]

在您的情况下,您的类型Function1[ Animal, R ] <: Function1[ Horse, R ](Any*) => Option[ List[ MyThing ] ] wrt。它的参数意味着contra-variant(int, String) => Option[ List[ MyThing ] ]的{​​{1}},这再次意味着您无法使用super-type代替(Any*) => Option[ List[ MyThing ] ]

您可以做的是为(int, String) => Option[ List[ MyThing ] ]

定义函数
(Any*) => Option[ List[ MyThing ] ]