【问题标题】:Type mismatch for function with Any* parameter带有 Any* 参数的函数的类型不匹配
【发布时间】:2015-02-28 16:04:47
【问题描述】:

我有这个方法:

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 进行重载? (就像使用 (int, String) => Option[List[MyThing]] for computeFunc 然后创建一个采用 computeFunc 的重载: (int, int, int, String) =>... 等)

谢谢。

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

【问题讨论】:

  • 您的部分问题是您的computeFunc 设置为为Any 类型的可变参数定义的函数,但您传递给getMachineResponse (computeKnownItems) 的函数不是定义为采用可变参数。 Function2[Int,String, Option[List[MyThing]]]Function1[Array[Any], Option[List[MyThing]] 之间没有自动类型兼容性,您的可变参数定义函数是
  • 我明白了,谢谢。我希望它是......例如在 C# 中,这可以通过“参数”轻松完成。我假设 * 和 Seq 是等价的。

标签: scala


【解决方案1】:

首先...我没有看到这个东西在编译。除了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 &lt;: Animal 的子类型。

现在,让我们考虑一个著名的类型 - List[ +T ]。现在为什么+ 符号...基本上+ 表示List[ T ]co-variant 用于type T,这意味着如果Horse &lt;: Animal 然后List[ Horse ] &lt;: List[ Animal ]。这反过来意味着您可以在需要List[ Animal ] 实例的任何地方传递List[ Horse ] 的实例。如果你仔细想想,即使是英语也是如此。

但是,如果您谈论函数,它们是contra-variant,考虑Function1[ -T, +R ],这意味着如果Horse &lt;: Animal 那么Function1[ Animal, R ]Function1[ Horse, R ]Function1[ Animal, R ] &lt;: Function1[ Horse, R ] 的子类型。

在您的情况下,您的类型 (Any*) =&gt; Option[ List[ MyThing ] ]contra-variant wrt。它的参数意味着(int, String) =&gt; Option[ List[ MyThing ] ]super-type(Any*) =&gt; Option[ List[ MyThing ] ] 这再次意味着你不能使用(int, String) =&gt; Option[ List[ MyThing ] ] 代替(Any*) =&gt; Option[ List[ MyThing ] ]

你可以做的是为Map[ String, Any ]定义函数

def getMachineResponse(computeFunc: ( Map[ String, Any ] ) => Option[List[MyThing]], any: Map[ String, Any ] ):  Route = {
  get {
    val things = computeFunc(any)
    // now do some stuff 
  }
}

private def computeKnownItems(myMap: Map[ String, Any] ): Option[ List[ MyThing ] ] = {
  val myType = myMap.get( "type" ).asInstanceOf[ Int ]
  val myId = myMap.get( "id" ).asInstanceOf[ String ]
  // get the things
}

【讨论】:

  • 我不确定这是否正确。 computeFunc 被定义为 Function1computeKnownItemsFunction2,我认为这是真正的问题。
  • 嗯......我也认为代码可能还有其他问题......但我非常确定的一件事是 - 你不能提供 (Int*) =&gt; R 来代替 @987654377 @.
  • 即使使用这个简单的东西,我也会遇到编译错误 - def simple( func: ( Int* ) =&gt; Int, ints: Int* ): Int = func( ints )...... error: type mismatch; found : Seq[Int] ; required: Int
  • 关于 type 是保留关键字,这是因为我在这里发布时编辑了实际功能。它在我的代码中称为 mType。错误信息与 cmbaxter 提到的一致。
  • @SarveshKumarSingh 您只需将 func: (Int*) 更改为 func(Seq[Int]) 即可编译该 sn-p(至少在 2.11 中对我而言)。
猜你喜欢
  • 2020-03-19
  • 2021-12-03
  • 2019-09-06
  • 2019-01-09
  • 2018-03-19
  • 2021-06-09
  • 1970-01-01
  • 2019-06-21
  • 2021-06-10
相关资源
最近更新 更多