2016-10-12 70 views
0

在下面的函數共同下界,Scala編譯器能夠定義的返回類型以在如果/ else表達式中使用的值的最低的共同父類型:定義的參數

def cond(b: Boolean, t: A, f: B) = if (b) t else f 

考慮以下層次結構:

class X 
class A extends X 
class B extends X 

上述函數cond被定義爲返回X類型的值。

但是,如果AB都在cond函數的定義類型的參數,它的返回類型爲Any

def cond[A, B](b: Boolean, t: A, f: B) = if (b) t else f 

是否有可能使編譯器使用類型的最低共同父參數?

我嘗試以下的一些變型中,沒有成功:

def cond[A, B, R >: A with B](b: Boolean, t: A, f: B): R = if (b) t else f 
def cond[A, B, R](b: Boolean, t: A, f: B)(implicit ev1: A <:< R, ev2: B <:< R): R = if (b) t else f 

EDIT:上面的問題是過分簡化。其實我真正的問題就已經解決了類型參數之一:

class C[A](b: Boolean, t: A) { 
    def cond[B](f: B) = if(b) t else f 
} 

回答

1

如果你不需要正序連贏類型的參數,那麼下面通常就足夠了:

def cond[T](b: Boolean, t: T, f: T) = if (b) t else f 

斯卡拉將自動上溯造型的類型參數的最小上界(LUB ):

scala> cond(true, new A, new B) 
res0: X = [email protected] 

但是如果你需要的確切類型,例如隱式的決定,我倍兒ieve以下伎倆應工作:

def cond[A, B, C >: A](b: Boolean, t: A, f: B with C): C = if (b) t else f 

這裏AB是準確的參數類型,以及C是他們的LUB。 C約束爲超類型AC >: A,但它也應該是第二個參數的類型,因爲它被定義爲f: B with C,因此它被推斷爲AB的LUB。

我們可以檢查正確的類型推斷這一定義與下面的代碼:

import reflect.runtime.universe._ 
def cond[A, B, C >: A](b: Boolean, t: A, f: B with C)(
    implicit ta: TypeTag[A], 
      tb: TypeTag[B], 
      tc: TypeTag[C] 
): C = { 
    println(ta) 
    println(tb) 
    println(tc) 
    if (b) t else f 
} 

scala> cond(true, new A, new B) 
TypeTag[A] 
TypeTag[B] 
TypeTag[X] 
res5: X = [email protected] 
1

你可以申請上界類型A和B,如果你知道LUB靜態。

def cond[A <: C, B <: C,C](b: Boolean, t: A, f: B) = if (b) t else f 
0

感謝@nikhil和@Kolmar答案我可以想出這種解決方案:

class C[A](b: Boolean, t: A) { 
    def cond[B <: R, R >: A](f: B): R = if(b) t else f 
}