2011-08-06 29 views
6

Belirli bir tür için varsayılan değeri sağlayan bir Default tip yazım oluşturmaya çalışıyorum. Ben bugüne kadar ile geldi budur: beklendiği gibi yerine null verir neredeKapalı parametre çözünürlüğü - önceliği ayarlama

trait Default[A] { 
    def value: A 
} 

object Default { 
    def withValue[A](a: A) = new Default[A] { 
    def value = a 
    } 

    def default[A : Default]: A = implicitly[Default[A]].value 

    implicit val forBoolean = withValue(false) 

    implicit def forNumeric[A : Numeric] = 
    withValue(implicitly[Numeric[A]].zero) 

    implicit val forChar = withValue(' ') 

    implicit val forString = withValue("") 

    implicit def forOption[A] = withValue(None : Option[A]) 

    implicit def forAnyRef[A >: Null] = withValue(null : A) 
} 

case class Person(name: String, age: Int) 

case class Point(x: Double, y: Double) 

object Point { 
    implicit val pointDefault = Default withValue Point(0.0, 0.0) 
} 

object Main { 
    def main(args: Array[String]): Unit = { 
    import Default.default 
    println(default[Int]) 
    println(default[BigDecimal]) 
    println(default[Option[String]]) 
    println(default[String]) 
    println(default[Person]) 
    println(default[Point]) 
    } 
} 

Yukarıdaki uygulama BigInt ve BigDecimal (ve Numeric örnekleri olan diğer kullanıcı tanımlı tipler) halleri hariç, davranır sıfır. forNumeric'un forAnyRef üzerinden öncelik kazanması için ne yapmalıyım ve beklediğim davranışı alıyorum?

cevap

11

forAnyRef bu için §6.26.3 Scala referans “Aşırı yükleme Çözünürlük” göre forNumeric daha daha özel çünkü kapalı seçilir. Orada böyle, Default uzanan bir özelliği taşıyarak önceliğini azaltmak için bir yoldur:

trait LowerPriorityImplicits extends LowestPriorityImplicits { 
    this: Default.type => 

    implicit def forAnyRef[A >: Null] = withValue(null: A) 

} 

object Default extends LowerPriorityImplicits { 
    // as before, without forAnyRef 
} 

Ama şimdi hem forAnyRef ve forNumeric birbirlerine olduğunca spesifik çünkü, hile sadece bir parçası olduğunu ve belirsiz-örtülü bir hata alırsınız. Neden? forAnyRef, A: A >: Null üzerinde önemsiz olmayan bir kısıtlamaya sahip olduğundan ek bir özellik noktası alır. Eğer forNumeric bir aşikar olmayan kısıtlama eklemek, daha sonra yapabilecekleriniz, Default bunu iki katına çıkarmak:

implicit def forNumericVal[A <: AnyVal: Numeric] = withValue(implicitly[Numeric[A]].zero) 

implicit def forNumericRef[A <: AnyRef: Numeric] = withValue(implicitly[Numeric[A]].zero) 

Şimdi, bu ek kısıtlama türleri için forAnyRef bir Numeric nerelerde olduğunu forNumericVal ve forNumericRef daha spesifik hale getirir

. cevap, Jean için

trait Default[A] { 
    def value: A 
} 

object Default extends LowPriorityImplicits { 
    def withValue[A](a: A) = new Default[A] { 
    def value = a 
    } 

    def default[A : Default]: A = implicitly[Default[A]].value 

    implicit val forBoolean = withValue(false) 

    implicit def forNumeric[A : Numeric] = 
    withValue(implicitly[Numeric[A]].zero) 

    implicit val forChar = withValue(' ') 

    implicit val forString = withValue("") 

    implicit def forOption[A] = withValue(None : Option[A]) 
} 

trait LowPriorityImplicits { this: Default.type => 
    implicit def forAnyRef[A](implicit ev: Null <:< A) = withValue(null : A) 
} 

case class Person(name: String, age: Int) 

case class Point(x: Double, y: Double) 

object Point { 
    implicit val pointDefault = Default withValue Point(0.0, 0.0) 
} 

object Main { 
    import Default.default 

    def main(args: Array[String]): Unit = { 
    println(default[Int]) 
    println(default[BigDecimal]) 
    println(default[Option[String]]) 
    println(default[String]) 
    println(default[Person]) 
    println(default[Point]) 
    } 
} 
+0

Teşekkür: Burada – missingfaktor

6

sorunu çözmek için başka bir yoludur, herhangi bir kod tekrarını gerektirmez. Çözümünüzü anlatarak bu küçük kod çoğaltmasını önleyen başka bir çözüm buldum. Okuyucuların yararı için aşağıda yazıyorum.
İlgili konular