102 votes

Quelles sont les règles précises pour la quelle vous pouvez omettre des points, des parenthèses, des accolades, = (fonctions), etc.. ?

Quelles sont les règles précises quand vous pouvez omettre (omettre) les parenthèses, les points, les accolades, = (fonctions), etc.?

Par exemple, (le service.findAllPresentations.obtenir.d'abord.les votes.taille) doit être equalTo(2).

  • service est mon objet
  • def findAllPresentations:Option[Liste[Présentation]]
  • votes retourne la Liste[Vote]
  • doit et être sont à la fois les fonctions de spécifications

Pourquoi je ne peux pas:

(service findAllPresentations get first votes size) must be equalTo(2)

?

L'erreur de compilation est:

"RestServicesSpecTest.c'.service.findAllPresentations de type L'Option[Liste[com.sharca.Présentation]] ne prend pas de paramètres"

Pourquoi ne fait-il penser que je suis en train de passer un paramètre? Pourquoi dois-je utiliser des points pour chaque appel de méthode?

Pourquoi faut - (service.findAllPresentations get first votes size) être equalTo(2) résultat:

"non trouvé: valeur première"

Pourtant, les "doit être equalTo 2" de (service.findAllPresentations.get.first.votes.size) doit être equalTo 2, qui est, le chaînage de méthode fonctionne bien? - objet de la chaîne chaîne chaîne param.

J'ai regardé à travers la Scala livre et le site web et ne peut pas vraiment trouver une explication complète.

Est-il en fait, comme Rob H explique dans un Débordement de Pile question quels sont les personnages puis-je omettre dans Scala?, que la seule valable en cas d'utilisation de l'omission d'un le". " est pour "opérande de l'opérateur opérande" opérations de style, et pas pour le chaînage de méthode?

85voto

Daniel C. Sobral Points 159554

Vous semblez avoir tombé sur la réponse. De toute façon, je vais essayer de le rendre clair.

Vous pouvez omettre dot lors de l'utilisation du préfixe, infixe et postfix notations, ce que l'on appelle opérateur de notation. Alors que l'aide de l'opérateur de notation, et alors seulement, vous pouvez omettre les parenthèses s'il y a moins de deux paramètres passés à la méthode.

Maintenant, l'opérateur de la notation est une notation pour la méthode d'appel, ce qui signifie qu'il ne peut pas être utilisé en l'absence de l'objet qui est appelé.

Je vais brièvement détail les notations.

Préfixe:

Seulement ~, !, + et - peut être utilisé en préfixe de notation. C'est la notation que vous utilisez lorsque vous écrivez !flag ou val liability = -debt.

Infix:

C'est la notation où la méthode apparaît entre un objet et ses paramètres. Les opérateurs arithmétiques tous ici.

Postfix:

Cette notation est utilisée lorsque la méthode suit un objet et ne reçoit pas de paramètres. Par exemple, vous pouvez écrire list tail, et c'est postfix notation.

Vous pouvez la chaîne d'infixe notation des appels sans problème, tant qu'aucune méthode n'est au cari. Par exemple, j'aime utiliser le style suivant:

(list
 filter (...)
 map (...)
 mkString ", "
)

C'est la même chose que:

list filter (...) map (...) mkString ", "

Maintenant, pourquoi suis-je à l'aide de parenthèses ici, si le filtre et la carte en prendre qu'un seul paramètre? C'est parce que je suis de passage des fonctions anonymes. Je ne peux pas mélanger les les fonctions anonymes définitions avec infixe de style parce que j'ai besoin d'une limite pour la fin de ma fonction anonyme. Aussi, la définition du paramètre de la fonction anonyme qui pourrait être interprété comme le dernier paramètre de la infix méthode.

Vous pouvez utiliser infixe avec plusieurs paramètres:

string substring (start, end) map (_ toInt) mkString ("<", ", ", ">")

Fonctions curryfiées sont difficile à utiliser avec la notation infixe. Les fonctions de pliage sont un exemple clair de ce qui suit:

(0 /: list) ((cnt, string) => cnt + string.size)
(list foldLeft 0) ((cnt, string) => cnt + string.size)

Vous devez utiliser des parenthèses à l'extérieur de l'infixe appel. Je ne suis pas sûr exactement les règles en jeu ici.

Maintenant, nous allons parler de postfix. Postfix peut être difficile à utiliser, car il ne peut jamais être utilisé n'importe où sauf à la fin d'une expression. Par exemple, vous ne pouvez pas effectuer les opérations suivantes:

 list tail map (...)

Parce que la queue n'apparaît pas à la fin de l'expression. Vous ne pouvez pas le faire soit:

 list tail length

Vous pouvez utiliser la notation infixe en utilisant des parenthèses pour marquer la fin d'expressions:

 (list tail) map (...)
 (list tail) length

J'espère que cela a effacé tous les doutes. Si non, il suffit de déposer un commentaire et je vais voir ce que je peux faire pour l'améliorer.

40voto

Antony Stubbs Points 4236

Définitions de classe:

val ou var peuvent être omis dans les paramètres de classe qui permettra de rendre le paramètre privé.

L'ajout de var ou val va l'amener à être public (c'est la méthode des accesseurs et des mutateurs sont générées).

{} peut être omis si la classe n'a pas de corps, qui est

class EmptyClass

L'instanciation de classe:

Les paramètres génériques peuvent être omises si elles peuvent être déduites par le compilateur. Toutefois, si vos types ne correspondent pas, alors le paramètre type est toujours inférer de sorte qu'il corresponde. Donc, sans en préciser le type, vous ne pouvez pas obtenir ce que vous attendez - que, compte tenu de

class D[T](val x:T, val y:T);

Cela vous donnera une erreur de type (Int trouvé, Chaîne attendue)

var zz = new D[String]("Hi1", 1) // type error

Alors que cela fonctionne très bien:

var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}

Parce que le paramètre de type T, on déduit que la moins fréquente supertype des deux - Tout.


La définition d'une fonction:

= peut être supprimé si la fonction renvoie l'Unité (rien).

{} pour le corps de la fonction peut être supprimé si la fonction est un seul état, mais seulement si l'instruction renvoie une valeur (vous avez besoin de l' = signe), qui est,

def returnAString = "Hi!"

mais cela ne fonctionne pas:

def returnAString "Hi!" // Compile error - '=' expected but string literal found."

Le type de retour de la fonction peut être omise si elle peut être déduite (une méthode récursive doit avoir son type de retour spécifiée).

() peut être supprimé si la fonction ne prend aucun argument, qui est,

def endOfString {
  return "myDog".substring(2,1)
}

qui par convention est réservée à des méthodes qui n'ont pas d'effets secondaires - plus sur cela plus tard.

() n'est pas réellement chuté en soi lors de la définition d'un passage par nom paramenter, mais il est en fait un assez sémantiquement différente de la notation, qui est,

def myOp(passByNameString: => String)

Dit pop prend un laissez-passer-par-nom de paramètre, ce qui résulte en une Chaîne de caractères (qui est, il peut être un bloc de code qui retourne une chaîne de caractères), par opposition aux paramètres de la fonction,

def myOp(functionParam: () => String)

qui dit myOp prend une fonction qui a zéro des paramètres et retourne une Chaîne de caractères.

(Vous l'esprit, de passer par paramètres de nom compilé en fonctions; il est tout simplement la syntaxe plus agréable.)

() peuvent être déposés dans le paramètre de la fonction de définition si la fonction ne prend qu'un seul argument, par exemple:

def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }

Mais si elle a plus d'un argument, vous devez inclure la (les):

def myOp2(passByNameString:(Int, String) => String) { .. }

Déclarations:

. peuvent être déposés à l'utilisation de l'opérateur de notation, qui peut seulement être utilisé pour des opérateurs infixes (opérateurs de méthodes qui prennent des arguments). Voir la réponse de Daniel pour plus d'informations.

  • . peut également être supprimée pour les fonctions de postfix liste de queue

  • () peut être supprimée pour les opérateurs de suffixe liste.queue

  • () ne peut pas être utilisé avec les méthodes définies comme suit:

    def aMethod = "hi!" // Missing () on method definition
    aMethod // Works
    aMethod() // Compile error when calling method
    

Parce que cette notation est réservée par la convention pour les méthodes qui n'ont pas d'effets secondaires, comme le numéro de Liste de la queue (qui est, l'invocation d'une fonction, sans effets secondaires signifie que la fonction n'a aucun effet observable, à l'exception de sa valeur de retour).

  • () peut être abandonnée pour l'opérateur de notation lors du passage dans un seul argument

  • () peut être nécessaire d'utiliser postfix opérateurs qui ne sont pas à la fin d'une instruction

  • () peut être nécessaire de désigner des instructions imbriquées, les extrémités des fonctions anonymes, ou pour les opérateurs qui prennent plus d'un paramètre

Lorsque vous appelez une fonction qui prend une fonction, vous ne pouvez pas omettre le () de l'intérieur de la définition de la fonction, par exemple:

def myOp3(paramFunc0:() => String) {
    println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work

Lorsque vous appelez une fonction qui prend un paramètre de nom, vous ne pouvez pas spécifier l'argument comme un paramètre moins fonction anonyme. Par exemple, étant donné:

def myOp2(passByNameString:Int => String) {
  println(passByNameString)
}

Vous devez l'appeler comme:

myOp("myop3")

ou

myOp({
  val source = sourceProvider.source
  val p = myObject.findNameFromSource(source)
  p
})

mais non:

myOp(() => "myop3") // Doesn't work

L'OMI, de l'utilisation excessive de l'abandon des types de retour peuvent être nocifs pour le code pour être ré-utilisé. Il suffit de regarder la spécification pour un bon exemple de la réduction de la lisibilité en raison du manque d'informations explicites dans le code. Le nombre de niveaux d'indirection pour réellement comprendre ce que le type d'une variable est peut être les noix. Nous espérons de meilleurs outils possible d'éviter ce problème et de garder notre code concis.

(OK, dans la quête de compiler une plus complète, concise réponse (si j'ai oublié quelque chose, ou bien quelque chose de faux ou inexact s'il vous plaît commentaire), j'ai ajouté au début de la réponse. Veuillez noter que ce n'est pas un langage de spécification, donc je ne suis pas en train de faire exactement académiquement correct - juste plus comme une carte de référence.)

12voto

Antony Stubbs Points 4236

Une collection de citations de donner un aperçu sur les différentes conditions de...

Personnellement, je pensais qu'il serais plus dans le cahier des charges. Je suis sûre qu'il doit être, je ne suis pas à la recherche pour les bons mots...

Il ya un couple de sources cependant, et j'ai recueilli leur ensemble, mais rien de vraiment complet / complet / compréhensible / qui explique les problèmes ci-dessus, pour moi...:

"Si un corps de méthode a plus d'un expression, vous devez l'entourer de accolades {...}. Vous pouvez omettre le accolades si le corps de la méthode n'a qu'un seul d'expression".

À partir du chapitre 2, "Type Moins, Faire Plus", de Programmation Scala:

"Le corps de la partie supérieure de la méthode vient après le signe égal ‘='. Pourquoi un signe d'égalité? Pourquoi ne pas simplement des accolades {...}, comme dans Java? Parce que des points-virgules, fonction des types de retour, la méthode de les arguments des listes, et même le frisé les croisillons sont parfois omis, à l'aide d'un signe égal empêche plusieurs l'analyse des ambiguïtés. À l'aide d'une égale signe nous rappelle également que, même les fonctions sont des valeurs en Scala, qui est compatible avec la Scala, à la soutien de programmation fonctionnelle, décrit dans plus en détail dans le Chapitre 8, Fonctionnelle La programmation Scala."

À partir du chapitre 1, "de Zéro à Soixante: Introduction à Scala", de Programmation Scala:

"Une fonction sans paramètres peuvent être déclaré sans parenthèses, dans lequel cas, il doit être appelé sans entre parenthèses. Ceci fournit un soutien pour l'Uniforme Principe de l'Accès aux, par exemple que l'appelant ne sais pas si l' le symbole est une variable ou une fonction sans paramètres.

Le corps de la fonction est précédé par "=" si elle renvoie une valeur (c'est à dire le retour le type est autre chose que de l'Unité), mais le type de retour et le "=" peut être omis lorsque le type est l'Unité (c'est à dire qu'il ressemble à une procédure, par opposition à un la fonction).

Accolades autour du corps ne sont pas nécessaire (si le corps est un seul expression); plus précisément, le corps d'une fonction est une expression, et tout l'expression de plusieurs parties doit être délimitée par des accolades (un expression avec une partie peut éventuellement être placé entre accolades)."

"Fonctions avec zéro ou un seul argument peut être appelé sans le point et entre parenthèses. Mais toute expression peut ont des parenthèses autour de lui, de sorte que vous pouvez omettre le point et d'utiliser entre parenthèses.

Et puisque vous pouvez utiliser des accolades n'importe où vous pouvez utiliser des parenthèses, vous pouvez omettre le point et de mettre en accolades, ce qui peut contenir plusieurs instructions.

Fonctions sans arguments peuvent être appelé sans les parenthèses. Pour exemple, la longueur() de la fonction La chaîne peut être invoquée comme "abc".longueur plutôt que de "abc".longueur(). Si l' la fonction est un Scala fonction définie sans parenthèses, alors la fonction doit être appelée sans parenthèses.

Par convention, les fonctions sans des arguments qui ont des effets secondaires, tels comme println, sont appelés à entre parenthèses; les sans-côté les effets sont appelés sans entre parenthèses."

D'après le blog de la Scala de Syntaxe Apprêt:

"Une définition de la procédure est une fonction définition où le type de résultat et le signe égal sont omis; ses la définition de l'expression doit être un bloc. E. g., def f (ps) {statistiques} est l'équivalent de def f (ps): Unit = {statistiques}.

Exemple 4.6.3 Ici est une déclaration et un de?la définition d'une procédure nommée écrire:

trait Writer {
    def write(str: String)
}
object Terminal extends Writer {
    def write(str: String) { System.out.println(str) }
}

Le code ci-dessus est implicitement terminé pour le code suivant:

trait Writer {
    def write(str: String): Unit
}
object Terminal extends Writer {
    def write(str: String): Unit = { System.out.println(str) }
}"

À partir de la spécification du langage:

"Avec des méthodes qui prennent seulement un seul paramètre, Scala permet au développeur pour remplacer la . avec un espace et d'omettre les parenthèses, permettant à l'opérateur syntaxe décrite dans notre opérateur d'insertion exemple. Cette syntaxe est utilisée dans d'autres lieux dans de la Scala API, tels que la construction de la Gamme instances:

val firstTen:Range = 0 to 9

Ici encore, (Int) est une vanille méthode déclarée à l'intérieur d'une classe (il y a effectivement quelques plus implicite les conversions de type ici, mais vous obtenez le la dérive)."

De Scala pour Java Réfugiés Partie 6: Arriver Sur Java:

"Maintenant, lorsque vous essayez de "m 0", Scala les rejets étant un opérateur unaire, sur les motifs de ne pas être valide (~, !, - et +). Elle constate que "m" est un objet valide -- c'est une fonction, pas une méthode, et toutes les fonctions sont objets.

En tant que "0" n'est pas valide Scala identifiant, il ne peut être ni un infix ni d'un suffixe de l'opérateur. Par conséquent, la Scala se plaint qu'il prévu ";" -- ce qui serait distinct deux (presque) valide les expressions: "m" et "0". Si vous avez inséré, puis il se qui m nécessite un argument, ou, à défaut, un "_" pour le transformer en une application partielle de la la fonction".

"Je crois que l'opérateur de style de syntaxe ne fonctionne que lorsque vous avez l'explicite objet sur le côté gauche. L' la syntaxe est destiné à vous permettre d'exprimer "opérande de l'opérateur opérande" style les opérations de façon naturelle."

Les caractères qui puis-je omettre dans Scala?

Mais ce qui me confond est cette citation:

"Il doit y avoir un objet à recevoir un appel de méthode. Par exemple, vous ne pouvez pas faire "println "Hello World!"" comme la println besoin d'un objet destinataire. Vous pouvez le faire "de la Console println "Hello World!"" qui répond à la nécessité."

Car autant que je peux voir, il est un objet de recevoir l'appel...

2voto

Antony Stubbs Points 4236

En fait, en deuxième lecture, c'est peut-être la clé:

Avec des méthodes qui prennent seulement un seul paramètre, Scala permet au développeur pour remplacer la . avec un espace et d'omettre les parenthèses

Comme mentionné sur le post de blog: http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6 .

Alors peut-être que c'est en fait un très stricte de syntaxe "sucre" qui seulement des œuvres où vous sont effectivement à l'appel d'une méthode sur un objet, qui prend un paramètre. par exemple

1 + 2
1.+(2)

Et rien d'autre.

Cela expliquerait mes exemples dans la question.

Mais comme je l'ai dit, si quelqu'un pouvait point être exactement où, dans la langue spec c'est spécifiée, ce serait bien apprécié.

Ok, certains gentil garçon (paulp_ de #scala) l'a souligné, où dans la langue spec de cette information est:

6.12.3: La priorité et l'associativité de l' les opérateurs de déterminer le groupement de les parties d'une expression comme suit.

  • Si il y a plusieurs infix opérations dans une expression, puis les opérateurs de priorité plus élevée lier de plus près que les opérateurs avec moins de la préséance.
  • Si il sont consécutifs infix opérations e0 op1 e1 op2 . . .opn fr avec les opérateurs op1, . . . , opn de la même ordre de priorité, puis tous ces les opérateurs doivent avoir la même l'associativité. Si tous les opérateurs sont associatifs gauche, la séquence est interprété comme (. . . (e0 op1 e1) op2 . . .) opn fr. Autrement, si tous les les opérateurs sont rightassociative, l' la séquence est interprété comme e0 op1 (e1 op2 (. . .opn fr) . . .).
  • Postfix opérateurs ont toujours priorité moins élevée des opérateurs infixes. E. g. e1 op1 op2 e2 est toujours équivalent à (e1 op1 e2) op2.

La partie droite de l'opérateur d'une associatifs gauche de l'opérateur peut consister en plusieurs arguments enfermé dans entre parenthèses, par exemple e op (e1, . . . ,fr). Cette expression est ensuite interprété comme e.op(e1, . . . ,fr).

De gauche associative opération binaire e1 op e2 est interprété comme e1.op(e2). Si l'op est rightassociative, le même l'opération est interprétée comme { val x=e1; e2.op(x ) }, où x est une nouvelle nom.

Hmm - pour moi, il n'a pas de maillage avec ce que je vois, ou je ne comprends pas ;)

2voto

user92983 Points 209

Il n'y a pas tout. Vous serez susceptibles de recevoir des conseils autour de si oui ou non la fonction a des effets secondaires. C'est faux. La correction est de ne pas utiliser d'effets secondaires à l'raisonnable de la mesure permise par la Scala. Dans la mesure où il ne peut pas, alors tous les paris sont éteints. Tous les paris. L'utilisation de parenthèses est un élément de l'ensemble "ensemble" et le superflu. Il ne fournit pas de valeur une fois que tous les paris sont éteints.

Ce conseil est essentiellement une tentative à un effet de système qui échoue (à ne pas confondre avec: il est moins utile que les autres de l'effet des systèmes).

Essayez de ne pas d'effets secondaires. Après cela, d'accepter que tous les paris sont éteints. Se cachant derrière une de facto syntaxique notation pour un effet de système peut et ne, seulement causer des dommages.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X