2015-01-26 82 views
0

考慮下面的(工作)段定義DenseVector和陣列之間的雙向隱式轉換:安排implicits優先斯卡拉

import scala.reflect.ClassTag 
import org.apache.spark.mllib.linalg.Vectors 
import breeze.linalg.{DenseVector => BDV} 

    implicit def bdvToSeq[T](vect: BDV[T])(implicit ct: ClassTag[T]): Seq[T] = vect.toArray.toSeq 

    implicit def arrayToVect(darr: Array[Double]): BDV[Double] 
    = new BDV(darr) 
    implicit def bdvToArray[T](vect: BDV[T])(implicit ct: ClassTag[T]): Array[T] = vect.toArray 

    def add(v1: BDV[Double], v2: BDV[Double]) = 
    v1.zip(v2).map { x => x._1 + x._2} 

讓我們嘗試一下:

scala> arr.allVisitableIndicesActive // Array to DenseVector implicit conversion 
res4: Boolean = true 

scala> val d = new BDV(Array(77.7, 88.8, 99.9)) 
d: breeze.linalg.DenseVector[Double] = DenseVector(77.7, 88.8, 99.9) 

現在另一個方向:

scala> def myArrMethod(arr: Array[Double]) = println(arr.mkString(",")) 
myArrMethod: (arr: Array[Double])Unit 

scala> myArrMethod(d) // DenseVector to array conversion 
77.7,88.8,99.9 

以下也有效:注意darr。 toSeq

def norm(darr: Array[Double]): Double = { 
    Math.sqrt(darr.toSeq.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)}) 
    } 

但是,如果我們忽略.toSeq那麼我們implicits碰撞:

scala> def norm(darr: Array[Double]): Double = { 
     Math.sqrt(darr.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)}) 
     } 
<console>:34: error: type mismatch; 
found : darr.type (with underlying type Array[Double]) 
required: ?{def foldLeft(x$1: ? >: Double(0.0)): ?} 
Note that implicit conversions are not applicable because they are ambiguous: 
both method doubleArrayOps in object Predef of type (xs: Array[Double])scala.collection.mutable.ArrayOps[Double] 
and method arrayToVect of type (darr: Array[Double])breeze.linalg.DenseVector[Double] 
are possible conversion functions from darr.type to ?{def foldLeft(x$1: ? >: Double(0.0)): ?} 
      Math.sqrt(darr.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)}) 
        ^
<console>:34: error: value foldLeft is not a member of Array[Double] 
      Math.sqrt(darr.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)}) 

我卻不想把 「.toSeq」 作了明確規定。

所以我的問題是:如何設置正確的優先級,以便Predef.toSeq是明確的贏家 - 在自定義較低優先級隱含在上面定義之前總是嘗試嘗試?

回答

1

您可以提取所有的隱式轉換成目標,並將其導入只在需要的地方

trait BDVImplicits { 
    implicit def bdvToSeq[T](vect: BDV[T])(implicit ct: ClassTag[T]): Seq[T] = 
    vect.toArray.toSeq 

    implicit def arrayToVect(darr: Array[Double]): BDV[Double] = 
    new BDV(darr) 

    implicit def bdvToArray[T](vect: BDV[T])(implicit ct: ClassTag[T]): Array[T] = 
    vect.toArray 
} 

object BDVImplicits extends BDVImplicits 

如果您需要將您的「規範」方法utils的,例如,不導入隱含你」會很好。你只需要在你調用Util方法的類中導入BDVImplicits._。

我認爲這是最簡單的解決方法。

+0

感謝您的提示。對於延遲抱歉:我不得不重新安排項目來解決這個問題,之前可以驗證是否需要建立一個單獨的測試平臺。我會upvote(雖然還沒有接受),因爲這個概念在任何情況下都是有用的。 – javadba 2015-01-27 18:39:28