2016-03-31 24 views
1

我有這樣定義的類:如何在調用函數時指定一個類型參數,同時讓編譯器推斷另一個?

implicit class TraversableLikeView[+A, +Repr, Raw](self: Raw)(implicit cast: Raw => TraversableLike[A,Repr]) { 

    def filterByType[B, That](implicit bf: CanBuildFrom[Repr, B, That]): That = { 
     val result = cast(self).flatMap{ 
     case tt: B => Some(tt) 
     case _ => None 
     }(bf) 
     result 
    } 
    } 

當調用它TraversableLikeView("abc" :: "def" :: Nil)

欲類型參數B中指定,和類型參數That從預定義的implicits自動推斷。所以我這樣調用該函數:

TraversableLikeView("abc" :: "def" :: Nil).filterByType[String, _].foreach{...} 

然而,編譯器給了我這個錯誤:

Error:(38, 56) unbound wildcard type 
     ....filterByType[String, _].foreach{... 
          ^

爲什麼Scala是無法推斷出這種類型的參數?我該怎麼做才能解決它?

更新:我能得到最接近的事是這樣的:

implicit class TraversableLikeView[A, Repr, Raw <% TraversableLike[A, Repr]](self: Raw) { 

    def filterByType[B] = new FilterByType[B] 

    class FilterByType[B] { 

     def apply[That](implicit bf: CanBuildFrom[Repr, B, That]): That = { 
     val result = self.flatMap{ 
      case tt: B => Some(tt) 
      case _ => None 
     }(bf) 
     result 
     } 
    } 
    } 

    test("1") { 

    val res: Seq[String] = Seq("abc", "def").filterByType[String].apply 
    println(res) 

    val res2: Array[String] = Array("abc", "def").filterByType[String].apply 
    println(res2) 

    val res3: Set[String] = Set("abc", "def").filterByType[String].apply 
    println(res3) 
    } 

但是編譯器似乎未能在尋找證據(這甚至不應該需要):

Error:(38, 33) value filterByType is not a member of Array[com.tribbloids.spookystuff.pages.PageLike] 
     val unfetched = pageLikes.filterByType[Unfetched].head 
           ^

如果我放棄視圖邊界,它將完美工作(當然除了數組[String]),但是我很驚訝地發現它需要這樣的規避才能在scala中實現一個簡單的事情。

回答

1

您不能只指定兩個類型參數中的一個,並且要推斷另一個。您可以省略這些類型或將它們都指定。

你真的需要使用TraversableLike並查看邊界嗎? 如何只使用這樣的磁鐵模式:

trait FilterMagnet[A, B] { 
    type Out 
    def apply(self: Traversable[A]): Out 
    } 
    object FilterMagnet { 
    implicit def forThat[A, B: ClassTag, That](implicit bf: CanBuildFrom[Traversable[A], B, That]) = new FilterMagnet[A, B] { 
     type Out = That 
     def apply(self: Traversable[A]): That = self.collect { case tt: B => tt } 
    } 
    } 

    implicit class TraversableLikeView[A, C[A0 <: A] <: Traversable[A0]](self: C[A]) { 
    def filterByType[B](implicit magnet: FilterMagnet[A, B]): magnet.Out = magnet(self) 
    } 

    val listResult = TraversableLikeView("abc" :: "def" :: 3 :: Nil).filterByType[String] 
    println(listResult) // prints List(abc, def) 

    val setResult = TraversableLikeView(Set("abc", 3, true, "def")).filterByType[String] 
    println(setResult) // prints Set(abc, def) 

不要忘記添加勢必能夠通過B來篩選ClassTag背景下,否則類型擦除不會讓你保持在大約運行信息B

+0

是的,它使用的視圖的約束,否則該功能將不會如工作是非常重要的陣列( 「一」, 「B」)。此外,這不是一個完美的解決方案,因爲listResult&setResult的編譯類型仍然是Traversable [String] – tribbloid

1

一個解決這個問題的兩種方法之間的分裂你的類型參數:

class FilterByType[B] { 
    def apply[That](implicit bf: CanBuildFrom[Repr, B, That]): That = { 
    val result = cast(self).flatMap{ 
     case tt: B => Some(tt) 
     case _ => None 
    }(bf) 
    result 
    } 
} 

def filterByType[B] = new FilterByType[B] 

TraversableLikeView("abc" :: "def" :: Nil).filterByType[String].apply.foreach{...} 
+0

稍微好一點的解決方案,但是沒有視圖邊界,我仍然無法在Array [String]上使用它。請允許我將第一類和函數移動到隱式視圖以避免混淆 – tribbloid

+0

剛剛發現了另一個問題:如果使用.filterByType [Int],它將始終返回空列表,而不管內容如何。只有filterByType [java.lang.Integer]的作品,這是一個已知的Scala 2.10的錯誤,但到目前爲止我還沒有找到一個快速規避 – tribbloid

相關問題