2010-02-25 21 views
11

Ho provato due modi per vincolare un parametro di tipo generico a un tipo nullable, ma entrambi sembrano avere alcuni problemi imprevisti.Come funzionano i limiti generici di scala per i tipi nullable

Primo tentativo (con T <: AnyRef):

scala> def testAnyRefConstraint[T <: AnyRef](option:Option[T]):T = { 
    | //without the cast, fails with compiler error: 
    | // "found: Null(null) required: T" 
    | option getOrElse null.asInstanceOf[T] 
    | } 
testAnyRefConstraint: [T <: AnyRef](Option[T])T 

scala> testAnyRefConstraint(Some("")) 
res0: java.lang.String = 

scala> testAnyRefConstraint(Some(0)) 
<console>:16: error: inferred type arguments [Int] do not conform to method testAnyRefConstraint's type parameter bounds [T <: AnyRef] 
     testAnyRefConstraint(Some(0)) 

Questo sembra fare esattamente quello che voglio, ma non capisco il motivo per cui l'ipotesi nulla deve essere gettato ad un T.


secondo tentativo (con T>: Null):

scala> def testNullConstraint[T >: Null](option:Option[T]):T = { 
    | option getOrElse null 
    | } 
testNullConstraint: [T >: Null](Option[T])T 

scala> testNullConstraint(Some("")) 
res2: java.lang.String = 

scala> testNullConstraint(Some(0)) 
res3: Any = 0 

Ciò non richiede il cast sul nulla, ma permette a AnyVals di essere passato e converte il tipo in qualsiasi, che non è quello che stavo cercando.

Qualcuno ha idea del perché questi due diversi approcci funzionino nel modo in cui lo fanno?

risposta

20
def testAnyRefConstraint[T >: Null <: AnyRef](option:Option[T]):T = { 
    option getOrElse null 
} 

Mi sono sentito davvero stupido quando ho fatto questo errore la prima volta. Solo perché qualcosa si estende AnyRef non significa che deve essere annullabile. Ad esempio, Nothing è un sottotipo di AnyRef e non è annullabile.

Viceversa è simile, perché Any è un supertipo di Null e ogni Int è anche un Any.

Problemi correlati