web-dev-qa-db-fra.com

Est-ce la bonne façon d'initialiser les références nulles dans Scala?

Disons que j'ai une instance MyObject qui n'est pas initialisée:

var a:MyObject = null

est-ce la bonne façon de l'initialiser à null?

50
Geo

Des alternatives

Utilisez null en dernier recours. Comme déjà mentionné, Option remplace la plupart des utilisations de null. Si vous utilisez null pour implémenter l'initialisation différée d'un champ avec un calcul coûteux, vous devez utiliser un lazy val.

Initialisation canonique à null

Cela dit, Scala supporte null. Personnellement, je l'utilise en combinaison avec Spring Dependency Injection.

Votre code est parfaitement valide. Cependant, je vous suggère d'utiliser var t: T = _ pour initialiser t à sa valeur par défaut. Si T est une primitive, vous obtenez la valeur par défaut spécifique au type. Sinon, vous obtenez null.

Non seulement ceci est plus concis, mais il est nécessaire quand vous ne savez pas à l'avance ce que sera T:

scala> class A[T] { var t: T = _ }
defined class A

scala> new A[String].t
res0: String = null

scala> new A[Object].t            
res1: Java.lang.Object = null

scala> new A[Int].t   
res2: Int = 0

scala> new A[Byte].t
res3: Byte = 0

scala> new A[Boolean].t
res4: Boolean = false

scala> new A[Any].t   
res5: Any = null

Avancée

Utiliser var t: T= null est une erreur de compilation si T n'est pas lié:

scala> class A[T] { var t: T = null }
<console>:5: error: type mismatch;
 found   : Null(null)
 required: T
       class A[T] { var t: T = null }

Vous pouvez ajouter un paramètre implicite comme preuve que T est nullable - un sous-type de AnyRef n'est pas un sous-type de NotNull Ce n'est pas entièrement baked , même dans Scala 2.8. 

scala> class A[T](implicit ev: Null <:< T) { var t: T = null }           
defined class A
59
retronym

La réponse canonique est n'utilisez pas null . Au lieu de cela, utilisez un type d'option:

var a = None : Option[MyObject]

Quand vous voulez le définir:

a = Some(foo)

Et quand vous voulez le lire, testez None:

a match {
  case None => Console.println("not here")
  case Some(value) => Console.println("got: "+value)
}
31
David Crawshaw

Comme David et retronym l'ont déjà mentionné, c'est une bonne idée d'utiliser Option dans la plupart des cas, car Option rend plus évident le fait que vous devez gérer une situation sans résultat. Cependant, renvoyer Some(x) nécessite la création d'un objet et appeler .get ou .getOrElse peut coûter plus cher qu'une instruction if. Ainsi, dans le code haute performance, utiliser Option n'est pas toujours la meilleure stratégie (en particulier dans le code de recherche de collection, où vous pouvez rechercher une valeur très souvent et ne pas vouloir en conséquence de nombreuses créations d'objet). Là encore, si vous faites quelque chose comme retourner le texte d’une page Web entière (qui n’existera peut-être pas), il n’ya aucune raison que not n’utilise pas Option.

En outre, juste pour ajouter au commentaire de retronym sur les génériques avec null, vous pouvez le faire de manière complètement cuite si vous voulez vraiment dire que ce devrait être null:

class A[T >: Null] { var t: T = null }

et cela fonctionne en 2.7 et 2.8. C'est un peu moins général que la méthode <:<, car elle n'obéit pas à NotNull autant que je sache, mais elle fait exactement ce que vous espériez.

8
Rex Kerr

Je suis tombé sur cette question car scalastyle m'a dit de ne pas utiliser null lors de l'initialisation d'un objet dans mon test avec null

Ma solution sans changer aucun type qui satisfasse scalastyle:

var a: MyObject = (None: Option[MyObject]).orNull
0
Guenter