Quelles sont les règles précises pour lesquelles vous pouvez omettre (omettre) les parenthèses, les points, les accolades, = (fonctions), etc.?
Par exemple,
(service.findAllPresentations.get.first.votes.size) must be equalTo(2).
service
est mon objetdef findAllPresentations: Option[List[Presentation]]
votes
RetourList[Vote]
- doit et être sont tous deux des fonctions de spécifications
Pourquoi je ne peux pas y aller:
(service findAllPresentations get first votes size) must be equalTo(2)
?
L'erreur du compilateur est:
"RestServicesSpecTest.this.service.findAllPresentations de type Option [List [com.sharca.Presentation]] ne prend pas de paramètres"
Pourquoi pense-t-il que j'essaye de passer un paramètre? Pourquoi dois-je utiliser des points pour chaque appel de méthode?
Pourquoi doit (service.findAllPresentations get first votes size)
être égal à (2) aboutir à:
"introuvable: valeur en premier"
Pourtant, le "doit être égal à 2" de
(service.findAllPresentations.get.first.votes.size)
doit être égal à 2, c'est-à-dire que le chaînage de méthodes fonctionne bien? - Paramètre de chaîne de chaîne d'objets.
J'ai parcouru le livre et le site Web de Scala et je ne trouve pas vraiment d'explication complète.
Est-ce en fait, comme Rob H l'explique dans la question Stack Overflow Quels caractères puis-je omettre dans Scala? , que le seul cas d'utilisation valide pour omettre le "." est pour les opérations de style "opérande opérateur opérande", et non pour le chaînage de méthodes?
Définitions de classe:
val
ouvar
peut être omis des paramètres de classe, ce qui rendra le paramètre privé.L'ajout de var ou val le rendra public (c'est-à-dire que des accesseurs de méthode et des mutateurs sont générés).
{}
peut être omis si la classe n'a pas de corps, c'est-à-direInstanciation de classe:
Les paramètres génériques peuvent être omis s'ils peuvent être déduits par le compilateur. Cependant, notez que si vos types ne correspondent pas, alors le paramètre de type est toujours déduit pour qu'il corresponde. Donc, sans spécifier le type, vous n'obtiendrez peut-être pas ce que vous attendez - c'est-à-dire étant donné
Cela vous donnera une erreur de type (Int trouvé, chaîne attendue)
Alors que cela fonctionne bien:
Parce que le paramètre de type, T, est inféré comme le supertype le moins commun des deux - Any.
Définitions des fonctions:
=
peut être supprimée si la fonction renvoie Unit (rien).{}
car le corps de la fonction peut être supprimé si la fonction est une seule instruction, mais uniquement si l'instruction renvoie une valeur (vous avez besoin du=
signe), c'est-à-diremais cela ne fonctionne pas:
Le type de retour de la fonction peut être omis s'il peut être déduit (une méthode récursive doit avoir son type de retour spécifié).
()
peut être abandonné si la fonction ne prend aucun argument, c'est-à-direqui par convention est réservé aux méthodes qui n'ont pas d'effets secondaires - nous en parlerons plus tard.
()
n'est pas réellement abandonné en soi lors de la définition d'un paramètre de passage par nom , mais il s'agit en fait d'une notation assez sémantiquement différente, c'est-à-direDit que myOp prend un paramètre pass-by-name, qui aboutit à une chaîne (c'est-à-dire qu'il peut s'agir d'un bloc de code qui renvoie une chaîne) par opposition aux paramètres de fonction,
qui dit
myOp
prend une fonction qui n'a aucun paramètre et renvoie une chaîne.(Remarquez que les paramètres de passage par nom sont compilés en fonctions; cela rend simplement la syntaxe plus agréable.)
()
peut être supprimée dans la définition du paramètre de fonction si la fonction ne prend qu'un seul argument, par exemple:Mais si cela prend plus d'un argument, vous devez inclure le ():
Déclarations:
.
peuvent être supprimés pour utiliser la notation d'opérateur, qui ne peut être utilisée que pour les opérateurs d'infixe (opérateurs de méthodes qui prennent des arguments). Voir la réponse de Daniel pour plus d'informations..
peut également être supprimé pour les fonctions postfix list tail()
peut être supprimé pour les opérateurs postfix list.tail()
ne peut pas être utilisé avec les méthodes définies comme:Parce que cette notation est réservée par convention pour les méthodes qui n'ont pas d'effets secondaires, comme List # tail (c'est-à-dire que 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 supprimé pour la notation d'opérateur lors de la transmission d'un seul argument()
peut être nécessaire d'utiliser des opérateurs postfix qui ne sont pas à la fin d'une instruction()
peut être nécessaire pour désigner des instructions imbriquées, des fins de fonctions anonymes ou pour des opérateurs qui prennent plus d'un paramètreLorsque vous appelez une fonction qui prend une fonction, vous ne pouvez pas omettre le () de la définition de fonction interne, par exemple:
Lorsque vous appelez une fonction qui prend un paramètre par nom, vous ne pouvez pas spécifier l'argument en tant que fonction anonyme sans paramètre. Par exemple, étant donné:
Vous devez l'appeler comme suit:
ou
mais non:
OMI, la surutilisation de la suppression des types de retour peut être préjudiciable à la réutilisation du code. Il suffit de regarder les spécifications pour un bon exemple de lisibilité réduite en raison du manque d'informations explicites dans le code. Le nombre de niveaux d'indirection pour déterminer réellement quel est le type d'une variable peut être fou. Espérons que de meilleurs outils peuvent éviter ce problème et garder notre code concis.
(OK, dans le but de compiler une réponse plus complète et concise (si j'ai manqué quelque chose, ou quelque chose de mal / inexact, veuillez commenter), j'ai ajouté au début de la réponse. Veuillez noter que ce n'est pas une langue spécification, donc je n'essaye pas de la rendre exactement correcte sur le plan académique - mais plutôt comme une carte de référence.)
la source
Une collection de citations donnant un aperçu des différentes conditions ...
Personnellement, je pensais qu'il y aurait plus dans la spécification. Je suis sûr qu'il doit y en avoir, je ne cherche simplement pas les bons mots ...
Il existe cependant quelques sources, et je les ai rassemblées ensemble, mais rien de vraiment complet / complet / compréhensible / qui m'explique les problèmes ci-dessus ...:
Du chapitre 2, "Tapez moins, faites plus", de Programming Scala :
Du chapitre 1, "Zero to Sixty: Introducing Scala", de Programming Scala :
De l'article de blog Scala Syntax Primer :
À partir de la spécification de langue:
De Scala pour les réfugiés Java, partie 6: surmonter Java :
Quels personnages puis-je omettre dans Scala?
Mais ce qui me trouble aussi, c'est cette citation:
Car d'après ce que je peux voir, il y a un objet pour recevoir l'appel ...
la source
Je trouve plus facile de suivre cette règle empirique: dans les expressions, les espaces alternent entre les méthodes et les paramètres. Dans votre exemple,
(service.findAllPresentations.get.first.votes.size) must be equalTo(2)
analyse comme(service.findAllPresentations.get.first.votes.size).must(be)(equalTo(2))
. Notez que les parenthèses autour des 2 ont une associativité plus élevée que les espaces. Les points ont également une associativité plus élevée, ils(service.findAllPresentations.get.first.votes.size) must be.equalTo(2)
seraient donc analysés comme(service.findAllPresentations.get.first.votes.size).must(be.equalTo(2))
.service findAllPresentations get first votes size must be equalTo 2
analyse commeservice.findAllPresentations(get).first(votes).size(must).be(equalTo).2
.la source
En fait, en deuxième lecture, c'est peut-être la clé:
Comme mentionné sur le billet de blog: http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6 .
Alors peut-être est-ce en fait un "sucre de syntaxe" très strict qui ne fonctionne que là où vous appelez effectivement une méthode, sur un objet, qui prend un paramètre . par exemple
Et rien d'autre.
Cela expliquerait mes exemples dans la question.
Mais comme je l'ai dit, si quelqu'un pouvait indiquer exactement où dans la spécification de la langue cela est spécifié, ce serait très apprécié.
Ok, un gentil garçon (paulp_ de #scala) a indiqué où dans la spécification du langage cette information se trouve:
Hmm - pour moi, cela ne correspond pas à ce que je vois ou je ne le comprends tout simplement pas;)
la source
Il n'y en a pas. Vous recevrez probablement des conseils pour savoir si la fonction a ou non des effets secondaires. C'est faux. La correction consiste à ne pas utiliser les effets secondaires dans la mesure raisonnable autorisée par Scala. Dans la mesure où il ne le peut pas, tous les paris sont ouverts. Tout paris. L'utilisation de parenthèses est un élément de l'ensemble "tout" et est superflue. Il ne fournit aucune valeur une fois que tous les paris sont ouverts.
Ce conseil est essentiellement une tentative d'un système d'effets qui échoue (à ne pas confondre avec: est moins utile que les autres systèmes d'effets).
Essayez de ne pas avoir d'effets secondaires. Après cela, acceptez que tous les paris soient ouverts. Se cacher derrière une notation syntaxique de facto pour un système d'effets peut et ne fait que causer du tort.
la source