簡體   English   中英

Scala:錯誤:缺少參數類型

[英]Scala: error: missing parameter type

我正在嘗試編寫一些庫函數來增強基本集合。 大部分都進​​展順利,但我遇到了這個問題。

class EnhancedGenTraversableLike[A, Repr <: GenTraversable[A]](self: GenTraversableLike[A, Repr]) {
  def mapValuesStrict[T, U, R, That](f: U => R)(implicit ev: A <:< (T, U), bf: CanBuildFrom[Repr, (T, R), That]) = {
    val b = bf(self.asInstanceOf[Repr])
    b.sizeHint(self.size)
    for ((k: T, v: U) <- self) b += k -> f(v)
    b.result
  }
}
implicit def enhanceGenTraversableLike[A, Repr <: GenTraversable[A]](self: GenTraversableLike[A, Repr]) = new EnhancedGenTraversableLike[A, Repr](self)

這是我去使用它時會發生什么:

scala> List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict((_:Int).toString)
res0: List[(Int, java.lang.String)] = List((1,2), (2,3), (3,4), (2,5))

scala> List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict(x => x.toString)
<console>:13: error: missing parameter type
              List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict(x => x.toString)
                                                            ^

因此Scala無法確定x的類型。

此答案表明Scala不使用一個參數來解析另一個參數,但是單獨的參數列表可以解決問題。 然而,在我的情況下,這並不容易,因為類型信息可以在隱式參數中找到。

有沒有辦法解決這個問題,這樣我每次調用方法時都不必指定類型?


更新:根據Owen的建議,我最終創建了一個特定於可遍歷對的豐富類:

class EnrichedPairGenTraversableLike[T, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]) {
  def mapValuesStrict[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = {
    val b = bf(self.asInstanceOf[Repr])
    b.sizeHint(self.size)
    for ((k: T, v: U) <- self) b += k -> f(v)
    b.result
  }
}
implicit def enrichPairGenTraversableLike[T, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]) = new EnrichedPairGenTraversableLike(self)

就在這里。 讓我舉一個簡單的例子。 我希望這也適用於您更復雜的用例。

說我們有

trait Foo[A]

class Bar {
    def methWithImplicits[A,B](f: A => B)(implicit foo: Foo[A]) = null
}

implicit def fooInt: Foo[Int] = null

現在這完全是你描述的問題,因為

(new Bar).methWithImplicits(x => x)

給出“缺少參數類型”。

所以我們想要做的是將隱式參數移動到顯式提供的函數“后面”,以便Scala 首先看到隱式參數。 好吧,我們可以這樣做的一種方法是添加一個額外的間接層:

class Bar {
    def methWithImplicits2[A](implicit foo: Foo[A]) = new {
        def apply[B](f: A => B) = null
    }
}

(new Bar).methWithImplicits2.apply(x => x)

這是有效的,雖然語法不是那么漂亮。 您可能會考慮使用語法的一種方法是查看當前的設計,看看是否可以隱式進入任何“早期”階段。 例如,由於mapValuesStrict方法僅在提供隱式時才有意義,因此您可以使隱式的對象屬性而不是傳遞給方法。

但如果在您的設計中不方便,您可以使用額外的隱式轉換來隱藏它。 這就是我們想要做的事情:

implicit def addFoo[A](bar: Bar)(implicit foo: Foo[A]) = new {
    def methWithImplicits3[B](f: A => B) = null
}

但不幸的是,我懷疑是Scala中的一個錯誤導致它搜索一個過於多態的隱式值,導致它抱怨:

could not find implicit value for parameter foo: test.Foo[A]

這只在使用隱式轉換時才會發生,這就是為什么我認為這是一個錯誤。 因此,我們可以進一步收回:(並且,需要-Xexperimental用於依賴方法類型):

trait FooWrapper {
    type AA
    val foo: Foo[AA]
}

implicit def wrapFoo[A](implicit theFoo: Foo[A]) = new FooWrapper {
    type AA = A
    val foo = theFoo
}

implicit def addFoo(bar: Bar)(implicit foo: FooWrapper) = new {
    def methWithImplicits3[B](f: foo.AA => B) = null
}

現在

(new Bar).methWithImplicits3(x => x)

效果很好;)


更新

在你的特定情況下,我認為你最好的辦法是將隱含的工作加入到enhanceGenTraversable ,但是,唉,需要同樣的黑客來解決可能的錯誤:

// Notice `ev` is now a field of the class
class EnhancedGenTraversableLike[A, Repr <: GenTraversable[A], T, U]
    (self: GenTraversableLike[A, Repr], ev: A <:< (T, U))
{
    def mapValuesStrict[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = {
        val b = bf(self.asInstanceOf[Repr])
        b.sizeHint(self.size)
        for ((k: T, v: U) <- self) b += k -> f(v)
        b.result
    }
}

// The Hack
trait WrappedPairBound[A] {
    type TT
    type UU
    val bound: A <:< (TT, UU)
}

implicit def wrapPairBound[A,T,U](implicit ev: A <:< (T,U)) = new WrappedPairBound[A] {
    type TT = T
    type UU = U
    val bound = ev
}

// Take the implicit here
implicit def enhanceGenTraversableLike[A, Repr <: GenTraversable[A]]
        (self: GenTraversableLike[A, Repr])(implicit ev: WrappedPairBound[A]) =
    new EnhancedGenTraversableLike[A, Repr, ev.TT, ev.UU](self, ev.bound)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM