Question

L'une des nouvelles fonctionnalités de Scala 2.8 sont des bornes de contexte. Qu'est-ce qu'un contexte lié et où est-il utile?

Bien sûr, je recherche d'abord (et trouvé par exemple cette ) mais je ne pouvais pas trouver des informations très claires et détaillées.

Était-ce utile?

La solution

Avez-vous trouvé cet article ? Il couvre la nouvelle fonctionnalité liée contexte, dans le contexte de l'amélioration du tableau.

En règle générale, un paramètre de type à contexte lié est de la forme [T: Bound]; il est étendu au paramètre scarole T avec un paramètre implicite de type Bound[T].

Considérons la méthode tabulate qui forme une matrice à partir des résultats de l'application une fonction donnée f sur une gamme de nombres de 0 jusqu'à une longueur donnée. Jusqu'à Scala 2.7, tabulate pourrait être écrit comme suit:

def tabulate[T](len: Int, f: Int => T) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

Dans Scala 2.8 ce n'est plus possible, car les informations d'exécution est nécessaire pour créer la représentation de droite Array[T]. On a besoin de fournir cette information en passant une ClassManifest[T] dans la méthode comme paramètre implicite:

def tabulate[T](len: Int, f: Int => T)(implicit m: ClassManifest[T]) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

En forme de raccourci, contexte lié peut être utilisé sur le paramètre de type T au lieu, ce qui donne:

def tabulate[T: ClassManifest](len: Int, f: Int => T) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

Autres conseils

La réponse de Robert couvre les détails techinal du contexte Bounds. Je vais vous donner mon interprétation de leur signification.

Dans Scala un Voir Bound (A <% B) capture le concept de « peut être considérée comme » (alors qu'une capture <: limite supérieure le concept de « est »). Un contexte lié (A : C) dit 'a un' sur un type. Vous pouvez lire les exemples sur les manifestes comme « T a Manifest ». L'exemple vous avez accédé à Ordered à propos de vs Ordering illustre la différence. Procédé

def example[T <% Ordered[T]](param: T)

indique que le paramètre peut être considéré comme un Ordered. Comparer avec

def example[T : Ordering](param: T)

qui indique que le paramètre a une Ordering associée.

En termes d'utilisation, il a fallu un certain temps pour que les conventions établies, mais les limites de contexte sont préférables aux limites de vue ( limites de vue sont maintenant déconseillés ). Une suggestion est qu'un contexte lié est préféré lorsque vous devez transférer une définition implicite d'une portée à l'autre sans avoir besoin de s'y référer directement (ce qui est certainement le cas pour le ClassManifest utilisé pour créer un tableau).

Une autre façon de penser à des bornes de vue et des limites de contexte est que les premiers transferts conversions implicites du champ d'application de l'appelant. Le second transfère les objets implicites du champ d'application de l'appelant.

(Ceci est une note entre parenthèses. Lire et comprendre les autres réponses en premier.)

Contexte Bounds généralisent en fait Voir Bounds.

Alors, étant donné ce code exprimé avec vue Bound:

scala> implicit def int2str(i: Int): String = i.toString
int2str: (i: Int)String

scala> def f1[T <% String](t: T) = 0
f1: [T](t: T)(implicit evidence$1: (T) => String)Int

Cela pourrait aussi être exprimée par un contexte lié, avec l'aide d'un alias de type représentant des fonctions de type de type F T.

scala> trait To[T] { type From[F] = F => T }           
defined trait To

scala> def f2[T : To[String]#From](t: T) = 0       
f2: [T](t: T)(implicit evidence$1: (T) => java.lang.String)Int

scala> f2(1)
res1: Int = 0

Un contexte lié doit être utilisé avec un constructeur de type de type * => *. Toutefois, le constructeur de type Function1 est de type (*, *) => *. L'utilisation de l'alias de type applique partiellement second paramètre de type avec le type String, ce qui donne un constructeur de type de type approprié pour être utilisé comme un contexte lié.

Il y a une proposition pour vous permettre d'exprimer directement types partiellement appliqués à Scala, sans l'utilisation de l'alias de type à l'intérieur d'un trait. Vous pouvez alors écrire:

def f3[T : [X](X => String)](t: T) = 0 

Ceci est une autre note entre parenthèses.

Ben a souligné , un contexte lié représente une « a-a » contrainte entre un paramètre de type et une classe de type. Autrement dit, il représente une contrainte qu'une valeur implicite d'une classe de type particulier existe.

Lors de l'utilisation d'un contexte lié, on a souvent besoin de surface que la valeur implicite. Par exemple, compte tenu de la T : Ordering de contrainte, on aura souvent besoin de l'instance de Ordering[T] qui satisfait la contrainte.

scroll top