Question

D'une certaine manière de simple, quelles sont les limites de contexte et afficher et quelle est la différence entre eux?

Voici quelques exemples faciles à suivre serait bien aussi!

Était-ce utile?

La solution

Je pensais que cela a déjà posé, mais, dans ce cas, la question n'est pas apparente dans la barre « liés ». Alors, voici:

Qu'est-ce qu'un Voir Bound?

voir lié est un mécanisme mis en place à Scala pour permettre l'utilisation d'un certain type A comme si il était un peu B type. La syntaxe typique est la suivante:

def f[A <% B](a: A) = a.bMethod

En d'autres termes, A devrait avoir une conversion implicite à B disponible, de sorte que l'on peut appeler des méthodes de B sur un objet de type A. Le plus usage courant des limites de vue dans la bibliothèque standard (avant Scala 2.8.0, de toute façon), est avec Ordered, comme ceci:

def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b

Parce que l'on peut convertir en un A Ordered[A], et parce que Ordered[A] définit la méthode <(other: A): Boolean, je peux utiliser l'expression a < b.

S'il vous plaît noter que limites de vue sont déconseillés , vous devez les éviter.

Qu'est-ce qu'un contexte Bound?

limites de contexte ont été introduites dans Scala 2.8.0, et sont généralement utilisés avec le soi-disant modèle de classe de type , un modèle de code qui émule les fonctionnalités fournies par les classes de type Haskell, bien que dans une plus verbeuse manière.

Alors qu'une vue lié peut être utilisé avec des types simples (par exemple, A <% String), un contexte lié nécessite une Type paramétrés , comme Ordered[A] ci-dessus, mais contrairement à String.

Un contexte lié décrit un implicite valeur , au lieu de vue lié de implicite conversion . Il est utilisé pour déclarer que, pour un certain type A, il y a une valeur implicite de type B[A] disponible. La syntaxe est la suivante:

def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]

Ceci est plus confuse que la vue liée parce qu'elle est pas immédiatement clair comment l'utiliser. L'exemple courant d'utilisation dans Scala est le suivant:

def f[A : ClassManifest](n: Int) = new Array[A](n)

Une initialisation de Array sur un type paramétrées nécessite un ClassManifest être disponible, pour des raisons liées à l'effacement Arcane de type et la nature non-effacement des tableaux.

Un autre exemple très commun dans la bibliothèque est un peu plus complexe:

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

Ici, implicitly est utilisé pour retrive la valeur implicite que nous voulons, un de type Ordering[A], qui classe définit la méthode compare(a: A, b: A): Int.

Nous verrons une autre façon de le faire ci-dessous.

Comment sont mises en œuvre View Bounds et contexte Bounds?

Il ne devrait pas être surprenant que les deux bornes de vue et les limites de contexte sont mises en œuvre avec des paramètres implicites, compte tenu de leur définition. En fait, la syntaxe je l'ai montré sont des sucres syntaxiques pour ce qui se passe vraiment. Voir ci-dessous comment ils de sucre:

def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod

def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)

Alors, naturellement, on peut les écrire dans leur syntaxe complète, ce qui est particulièrement utile pour les limites de contexte:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)

Que Voir Bounds utilisé?

bornes View sont utilisées principalement pour tirer profit du pimp ma bibliothèque modèle, à travers lequel on « ajoute » méthodes à une classe existante, dans des situations où vous voulez revenir en quelque sorte le type d'origine. Si vous n'avez pas besoin de retourner ce type de quelque façon, vous n'avez pas besoin d'une vue liée.

L'exemple classique de vue utilisation liée est la manipulation Ordered. Notez que Int est Ordered pas, par exemple, bien qu'il y ait une conversion implicite. L'exemple des besoins précédemment donné une vue liée car elle renvoie le type non converti:

def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b

Cet exemple ne fonctionnera pas sans limites de vue. Cependant, si je devais revenir un autre type, alors je ne pas besoin d'une vue plus lié:

def f[A](a: Ordered[A], b: A): Boolean = a < b

La conversion ici (si nécessaire) arrive avant que je passe le paramètre à f, so f n'a pas besoin de le savoir.

En plus Ordered, l'utilisation la plus courante de la bibliothèque gère String et Array, qui sont des classes Java, comme ils étaient collections Scala. Par exemple:

def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b

Si l'on a essayé de le faire sans bornes de vue, le type de retour d'un String serait WrappedString (Scala 2.8), et de même pour Array.

La même chose se produit même si le type est utilisé uniquement comme paramètre de type de type de retour:

def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted

Qu'est-ce que sont Bounds Contexte utilisé?

limites de contexte sont principalement utilisés dans ce qui est devenu connu sous le nom modèle classe de types , comme une référence aux classes de type Haskell. En fait, ce modèle met en œuvre une alternative à l'héritage en faisant des fonctionnalités disponibles à travers une sorte de modèle d'adaptation implicite.

L'exemple classique est la Ordering Scala 2.8, qui a remplacé Ordered tout au long de la bibliothèque de Scala. L'utilisation est:

def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b

Bien que vous verrez généralement que écrit comme ceci:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
    import ord.mkOrderingOps
    if (a < b) a else b
}

Quel tirer parti de certaines conversions implicites à l'intérieur Ordering qui permettent le style de l'opérateur historique. Un autre exemple Scala 2.8 est le Numeric:

def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)

Un exemple plus complexe est la nouvelle utilisation de la collection de CanBuildFrom, mais il y a déjà une très longue réponse à ce sujet, donc je vais l'éviter ici. Et, comme mentionné précédemment, il y a l'utilisation de ClassManifest, qui est nécessaire pour initialiser les nouveaux réseaux sans types concrets.

Le contexte lié au modèle de classe de types est beaucoup plus susceptible d'être utilisé par vos propres classes, car elles permettent la séparation des préoccupations, alors que les limites de vue peuvent être évités dans votre propre code de bonne conception (il est principalement utilisé pour se déplacer quelqu'un d'autre de conception).

Bien qu'il ait été possible depuis longtemps, l'utilisation des limites de contexte a réellement pris son envol en 2010, et se trouve maintenant dans une certaine mesure dans la plupart des bibliothèques et la plupart des cadres importants de Scala. L'exemple le plus extrême de son utilisation, cependant, est la bibliothèque Scalaz, qui apporte beaucoup de la puissance de Haskell à Scala. Je recommande la lecture sur les modèles de classe de types pour obtenir plus connaissance de toutes les façons dont il peut être utilisé.

EDIT

Questions connexes d'intérêt:

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top