2009-11-17 4 views

Répondre

30

Vous risquez de perdre une certaine sécurité et de provoquer une confusion éventuelle. Par exemple:

val iThinkThisIsAList = 2 
    for (i <- iThinkThisIsAList) yield { i + 1 } 

I (pour une raison quelconque) pensais avoir une liste, et il n'a pas pris dans le compilateur quand j'itéré parce qu'il a été converti automatiquement à une option [Int] .

Je dois ajouter que je pense que cela est un grand implicite d'avoir explicitement importé, tout probablement pas un défaut global.

+0

Au moins dans IntelliJ IDEA je peux voir quand quelque chose est auto-converti (par défaut il est souligné). Mais peut-être qu'il devrait y avoir un moyen de spécifier qu'une conversion implicite ne devrait avoir lieu que lors de la transmission de la valeur à une méthode, et non lors de l'appel d'une méthode. – herman

1

Il semblerait que cela pourrait être source de confusion pour les autres développeurs, car ils lisent votre code.

En général, il semble, implicit travaille pour aider cast d'un objet à un autre, pour découper le code de coulée confusion qui peut encombrer le code, mais, si j'ai une variable et il devient en quelque sorte un Some alors que cela semble être ennuyeux.

Vous pouvez mettre un peu de code montrant utilisé, pour voir comment il serait source de confusion.

+1

Je reçois votre dérive .. Cependant, le point de l'option [T] est qu'il peut contenir une valeur ou d'un Néant, il semble intuitif moi que si une méthode prend une variable de type Option [T] je devrais être capable de lui passer un T. Pouvez-vous penser à un exemple où vous pourriez avoir une certaine confusion, par ex. une variable devenant Un par inadvertance? –

-2

Cela me semble bon, sauf qu'il ne fonctionne pas pour un T primitif (qui ne peut être nulle). Je suppose qu'un générique non spécialisé obtient toujours des primitives en boîte, alors c'est probablement très bien.

25

Notez que vous pouvez utiliser le modèle explicit implicit qui éviterait la confusion et de garder le code laconique en même temps.

Ce que je veux dire par implicite explicite est plutôt que d'avoir une conversion directe T-Option[T] vous pourriez avoir une conversion à un objet enveloppe qui fournit les moyens de faire la conversion T-Option[T].

class Optionable[T <: AnyRef](value: T) { 
    def toOption: Option[T] = if (value == null) None else Some(value) 
} 

implicit def anyRefToOptionable[T <: AnyRef](value: T) = new Optionable(value) 

... je pourrais trouver un meilleur nom pour elle que Optionable, mais maintenant vous pouvez écrire du code comme:

val x: String = "foo" 
x.toOption // Some("foo") 

val y: String = null 
x.toOption // None 

Je crois que cette façon est totalement transparente et contribue à la compréhension des le code écrit - éliminant tous les contrôles pour null d'une manière agréable.

Notez le T <: AnyRef - vous ne devez effectuer cette conversion implicite que pour les types qui acceptent les valeurs null, qui sont par définition des types de référence.

+0

Salut Flaviu, suggestion intéressante. Je l'aime globalement - bien que je pense que cela rend mon problème pire pas mieux, maintenant au lieu de taper Some() je dois taper toOption ... mais il a l'avantage de travailler avec null. –

+6

'Option (x)' (au lieu de 'Some (x)') fonctionne aussi avec null. – schmmd

+2

@ flaviu-cipcigan, fait la même chose mais plus courte - classe implicite IntWithTimes [T] (x: T) { def àOption: Option [T] = si (x! = Null) Option (x) autre Aucune } – Maxim

11

Les lignes directrices générales pour les conversions implicites sont les suivantes:

  • Lorsque vous avez besoin d'ajouter des membres à un type (à la « classes ouvertes », alias le modèle « Pimp ma bibliothèque »), convertir en nouveau type qui étend AnyRef et qui définit uniquement les membres dont vous avez besoin.
  • Lorsque vous devez "corriger" une hiérarchie d'héritage.Ainsi, vous avez un certain type A qui devrait avoir sous-classé B, mais n'a pas pour une raison quelconque. Dans ce cas, vous pouvez définir une conversion implicite de A à B.

Ce sont les seulement où il est approprié de définir une conversion implicite. Toute autre conversion se heurte à des problèmes de sécurité et d'exactitude.

Cela n'a vraiment aucun sens pour T d'étendre Option[T], et évidemment le but de la conversion n'est pas simplement l'ajout de membres. Ainsi, une telle conversion serait déconseillée.

0

Vous pouvez également essayer de surcharger la méthode:

def having(key:String) = having(key, None) 

def having(key:String, default:String) = having(key, Some(default)) 

def having(key: String, default: Option[String]=Option.empty) : Create = { 
    keys += ((key, default)) 
    this 
} 
Questions connexes