J'ai récemment appris le langage de programmation Ruby, et dans l'ensemble c'est un bon langage. Mais j'ai été assez surpris de voir que ce n'était pas aussi simple que je m'y attendais. Plus précisément, la «règle de la moindre surprise» ne me paraissait pas très respectée (bien sûr, c'est assez subjectif). Par exemple:
x = true and false
puts x # displays true!
et le célèbre:
puts "zero is true!" if 0 # zero is true!
Quels sont les autres "Gotchas" dont vous avertiriez un débutant Ruby?
true and false
retourne vrai?Réponses:
Wikipédia Ruby gotchas
De l'article:
$
et@
n'indiquent pas le type de données variable comme en Perl, mais fonctionnent plutôt comme des opérateurs de résolution de portée.99.0
) ou une conversion explicite (99.to_f
). Il ne suffit pas d'ajouter un point (99.
), car les nombres sont sensibles à la syntaxe de la méthode.0
,""
et[]
sont tous évalués àtrue
. En C, l'expression est0 ? 1 : 0
évaluée à0
(c'est- à -dire faux). Dans Ruby, cependant, il cède1
, comme tous les nombres évaluent àtrue
; seulementnil
etfalse
évaluerfalse
. Un corollaire de cette règle est que les méthodes Ruby par convention - par exemple, les recherches d'expressions régulières - renvoient des nombres, des chaînes, des listes ou d'autres valeurs non fausses en cas de succès, maisnil
en cas d'échec (par exemple, incompatibilité). Cette convention est également utilisée dans Smalltalk, où seuls les objets spéciauxtrue
etfalse
peuvent être utilisés dans une expression booléenne.char
pour les caractères). Cela peut provoquer des surprises lors du découpage des chaînes:"abc"[0]
yields97
(un entier, représentant le code ASCII du premier caractère de la chaîne); pour obtenir l'"a"
utilisation"abc"[0,1]
(une sous-chaîne de longueur 1) ou"abc"[0].chr
.La notation
statement until expression
, contrairement aux déclarations équivalentes d'autres langages (par exempledo { statement } while (not(expression));
en C / C ++ / ...), n'exécute jamais l'instruction si l'expression l'est déjàtrue
. C'est parce questatement until expression
c'est en fait du sucre syntaxique sur, dont l'équivalent en C / C ++ est
while (not(expression)) statement;
commestatement if expression
est l'équivalent deCependant, la notation
dans Ruby exécutera en fait l'instruction une fois même si l'expression est déjà vraie.
Greeting << " world!" if Greeting == "Hello"
ne génère pas d'erreur ni d'avertissement. Ceci est similaire auxfinal
variables en Java, mais Ruby a également la fonctionnalité de "geler" un objet, contrairement à Java.Quelques fonctionnalités qui diffèrent notablement des autres langues:
Les opérateurs habituels des expressions conditionnelles,
and
etor
, ne suivent pas les règles normales de priorité:and
ne lie pas plus étroitement queor
. Ruby a également des opérateurs d'expression||
et&&
qui fonctionnent comme prévu.def
à l'intérieurdef
ne fait pas ce à quoi un programmeur Python pourrait s'attendre:Cela donne une erreur de
x
ne pas être défini. Vous devez utiliser un fichierProc
.Caractéristiques linguistiques
()
, pour éviter une signification ambiguë du code. Ne pas utiliser()
est encore une pratique courante, et peut être particulièrement agréable d'utiliser Ruby en tant que langage de programmation propre à un domaine lisible par l'homme, avec la méthode appeléemethod_missing()
.la source
Les débutants auront des problèmes avec les méthodes d'égalité :
Ces exemples devraient clarifier les 3 premières méthodes:
Notez que == , eql? et égal? doit toujours être symétrique: si a == b alors b == a.
Notez également que == et eql? sont tous deux implémentés dans la classe Object en tant qu'alias pour égaler? , donc si vous créez une nouvelle classe et que vous voulez == et eql? pour signifier autre chose qu'une simple identité, alors vous devez les remplacer tous les deux. Par exemple:
La méthode === se comporte différemment. Tout d'abord il n'est pas symétrique (a === b n'implique pas que b === a). Comme je l'ai dit, vous pouvez lire a === b comme "a correspond à b". Voici quelques exemples:
L' instruction case est basée sur la méthode === :
équivaut à ceci:
Si vous définissez une nouvelle classe dont les instances représentent une sorte de conteneur ou de plage (si elle a quelque chose comme une méthode include? Ou une correspondance? ), Vous trouverez peut-être utile de remplacer la méthode === comme ceci:
la source
Patching de singe . Ruby a des classes ouvertes, donc leur comportement peut être modifié dynamiquement au moment de l'exécution ...
Les objets peuvent répondre à des méthodes non définies si
method_missing
ousend
a été remplacé. Cela exploite l'invocation de méthode basée sur les messages de Ruby. Le système ActiveRecord de Rails l' utilise à bon escient.la source
Le code suivant m'a surpris. Je pense que c'est un piège dangereux: à la fois facile à utiliser et difficile à déboguer.
Cela imprime:
Mais si j'ajoute juste
comment =
quelque chose avant le bloc ...Ensuite, je reçois:
Fondamentalement, lorsqu'une variable n'est définie qu'à l'intérieur d'un bloc, elle est détruite à la fin du bloc, puis elle est réinitialisée à
nil
chaque itération. C'est généralement ce à quoi vous vous attendez. Mais si la variable est définie avant le bloc, alors la variable externe est utilisée à l'intérieur du bloc, et sa valeur est donc persistante entre les itérations.Une solution serait d'écrire ceci à la place:
Je pense que beaucoup de gens (moi y compris) ont tendance à écrire "
a = b if c
" au lieu de "a = (c ? b : nil)
", parce que c'est plus lisible, mais évidemment cela a des effets secondaires.la source
a = (b if c)
pour obtenir l'effet désiré, sans le ternaire. Ceci est dûb if c
auc
fait que la valeur est nulle si elle est fausse.Lors d'un appel
super
sans argument, la méthode surchargée est en fait appelée avec les mêmes arguments que la méthode surchargée.Pour appeler réellement
super
sans argument, vous devez diresuper()
.la source
B#hello
aname = 42
avant lesuper
, alors il dit "bonjour 42".Les blocs et les méthodes renvoient la valeur de la dernière ligne par défaut. L'ajout d'
puts
instructions à la fin à des fins de débogage peut provoquer des effets secondaires désagréablesla source
L'héritage ne joue aucun rôle dans la détermination de la visibilité des méthodes dans Ruby.
la source
J'ai eu beaucoup de mal à comprendre les variables de classe, les attributs de classe et les méthodes de classe. Ce code peut aider un débutant:
la source
une chose que j'ai apprise a été d'utiliser l'opérateur || = avec précaution. et faites particulièrement attention si vous avez affaire à des booléens. J'ai généralement utilisé a || = b comme fourre-tout pour donner à «a» une valeur par défaut si tout le reste échouait et que «a» restait nul. mais si a est faux et b est vrai, alors a sera assigné vrai.
la source
a = b if a.nil?
ou@a = b unless defined?(@a)
.Les blocs sont vraiment importants à comprendre, ils sont utilisés partout.
Vous n'avez pas besoin de parenthèses autour des paramètres de méthode. Que vous les utilisiez ou non dépend de vous. Certains disent que vous devriez toujours les utiliser .
Utilisez lever et sauvetage pour la gestion des exceptions, et non lancer et attraper.
Vous pouvez utiliser,
;
mais vous n'êtes pas obligé de le faire, sauf si vous souhaitez mettre plusieurs éléments sur une seule ligne.la source
J'ai eu des problèmes avec les mixins qui contiennent des méthodes d'instance et des méthodes de classe. Ce code peut aider un débutant:
Au début, je pensais que je pourrais avoir des modules avec des méthodes d'instance et des méthodes de classe en faisant simplement ceci:
Malheureusement, la méthode number_of_displays ne sera jamais incluse ou étendue car c'est une "méthode de classe de module". Seules les «méthodes d'instance de module» peuvent être incluses dans une classe (comme méthodes d'instance) ou étendues dans une classe (comme méthodes de classe). C'est pourquoi vous devez mettre les méthodes d'instance de votre mixin dans un module et les méthodes de classe de votre mixin dans un autre module (vous mettez généralement les méthodes de classe dans un sous-module "ClassMethods"). Grâce à la méthode magique incluse , vous pouvez faciliter l'inclusion à la fois des méthodes d'instance et des méthodes de classe dans un seul simple appel "include Displayable" (comme indiqué dans l'exemple ci-dessus).
Ce mixin comptera chaque affichage sur une base par classe . Le compteur est un attribut de classe, donc chaque classe aura le sien (votre programme échouera probablement si vous dérivez une nouvelle classe de la classe Person puisque le compteur @number_of_displays pour la classe dérivée ne sera jamais initialisé). Vous pouvez remplacer @number_of_displays par @@ number_of_displays pour en faire un compteur global. Dans ce cas, chaque hiérarchie de classes aura son propre compteur. Si vous voulez un compteur global et unique, vous devriez probablement en faire un attribut de module.
Tout cela n'était certainement pas intuitif pour moi lorsque j'ai commencé avec Ruby.
Je n'arrive toujours pas à comprendre comment rendre certaines de ces méthodes mixin privées ou protégées (seules les méthodes display et number_of_displays doivent être incluses en tant que méthodes publiques).
la source
Faites attention à la notation Range.
(Au moins, payer plus d' attention que je d' abord fait!)
Il y a une différence entre
0..10
(deux points) et0...10
(trois points).J'apprécie beaucoup Ruby. Mais cette chose point-point contre point-point-point me dérange. Je pense qu'une telle "caractéristique" à double syntaxe subtile est:
ne devrait pas être en mesure de provoquer des bogues dévastateurs dans mes programmes.
la source
for (i=0; i<max; i++)
etfor (i=0; i<=max; i++)
Je pense que "
and
" et "or
" sont des clin d'œil à Perl, qui est l'un des "parents" les plus évidents de Ruby (l'autre le plus important étant Smalltalk). Ils ont tous deux une priorité beaucoup plus faible (inférieure à l'affectation, en fait, d'où vient le comportement noté)&&
et||
quels sont les opérateurs que vous devriez utiliser.D'autres choses à savoir qui ne sont pas immédiatement évidentes:
Vous n'appelez pas vraiment des méthodes / fonctions, bien que cela ressemble un peu à cela. Au lieu de cela, comme dans Smalltalk, vous envoyez un message à un objet. Alors
method_missing
c'est vraiment plus commemessage_not_understood
.est équivalent à
Les symboles sont très largement utilisés. Ce sont ces choses qui commencent par
:
et elles ne sont pas immédiatement évidentes (enfin elles ne l'étaient pas pour moi), mais plus tôt vous les maîtriserez, mieux ce sera.Ruby est grand sur le "typage canard", suivant le principe que "s'il marche comme un canard et charlatan comme un canard ..." qui permet la substitution informelle d'objets avec un sous-ensemble commun de méthodes sans héritage explicite ni relation mixin.
la source
Si vous déclarez un setter (aka mutator) en utilisant
attr_writer
ouattr_accessor
(oudef foo=
), faites attention à ne pas l'appeler depuis l'intérieur de la classe. Puisque les variables sont implicitement déclarées, l'interpréteur doit toujours résoudrefoo = bar
en déclarant une nouvelle variable nommée foo, plutôt qu'en appelant la méthodeself.foo=(bar)
.Cela s'applique également aux objets Rails ActiveRecord, qui obtiennent des accesseurs définis en fonction des champs de la base de données. Puisqu'il ne s'agit même pas de variables d'instance @ -style, la bonne façon de définir ces valeurs individuellement est avec
self.value = 123
ouself['value'] = 123
.la source
Comprendre la différence entre la classe Heure et Date. Les deux sont différents et ont créé des problèmes lors de leur utilisation dans des rails. La classe Time est parfois en conflit avec d'autres bibliothèques de classes Time présentes dans la bibliothèque standard ruby / rails. Personnellement, il m'a fallu beaucoup de temps pour comprendre ce qui se passait exactement dans mon application rails. Plus tard, j'ai pensé quand je l'ai fait
Time.new
Il faisait référence à une bibliothèque dans un endroit dont je n'étais même pas au courant.
Désolé si je ne suis pas clair avec ce que je veux dire exactement. Si d'autres ont rencontré des problèmes similaires, veuillez expliquer à nouveau.
la source
Une chose qui m'a pris dans le passé est que la
\n
séquence d'échappement du caractère de nouvelle ligne ( ) - entre autres - n'est pas prise en charge par des chaînes entre guillemets simples. La barre oblique inverse elle-même est échappée. Vous devez utiliser des guillemets doubles pour que l'échappement fonctionne comme prévu.la source
0 et '' sont vrais, comme vous l'avez souligné.
Vous pouvez avoir une méthode et un module / classe du même nom (ce qui est logique, car la méthode est en fait ajoutée à Object et a donc son propre espace de noms).
Il n'y a pas d'héritage multiple, mais des "modules mixin" sont fréquemment utilisés pour ajouter des méthodes communes à plusieurs classes.
la source
false
etnil
sont les faux. Tous les autres sont de vraies valeurs.Les méthodes peuvent être redéfinies et peuvent devenir époustouflantes jusqu'à ce que vous en découvriez la cause. ( Certes, cette erreur est probablement un peu "difficile" à détecter quand l'action d'un contrôleur Ruby on Rails est redéfinie par erreur! )
Courir:
Mais appelez-le avec les avertissements activés et vous pouvez voir la raison:
la source
Je pense qu'il est toujours bon d'utiliser .length sur les choses ... puisque la taille est prise en charge par presque tout et que Ruby a des types dynamiques, vous pouvez obtenir des résultats vraiment étranges en appelant .size lorsque vous avez le mauvais type ... je préfère de loin obtenir a NoMethodError: méthode non définie `length ', donc je n'appelle généralement jamais size sur les objets dans Ruby.
m'a mordu plus d'une fois.
Souvenez-vous également que les objets ont des identifiants, donc j'essaie de ne pas utiliser les variables call id ou object_id juste pour éviter toute confusion. Si j'ai besoin d'un identifiant sur un objet Users, il est préférable de l'appeler quelque chose comme user_id.
Juste mes deux cents
la source
Je suis nouveau sur ruby, et lors de mon premier tour, j'ai rencontré un problème concernant la modification des flottants / chaînes en entier. J'ai commencé avec les flotteurs et j'ai tout codé comme f.to_int . Mais quand j'ai continué et utilisé la même méthode pour les chaînes, j'ai été lancé une courbe quand il s'agissait d'exécuter le programme.
Apparemment, une chaîne n'a pas de méthode to_int , mais les floats et les ints en ont.
Des parenthèses arbitraires m'ont également jeté au début. J'ai vu du code avec et d'autres sans. Il m'a fallu un certain temps pour réaliser que les deux styles sont acceptés.
la source
Lié à la réponse de monkut, Ruby
to_foo
méthodes indiquent à quel point une conversion sera stricte.Les plus courts comme
to_i
,to_s
dites-lui d'être paresseux et convertissez-les en type cible même s'ils ne peuvent pas être représentés avec précision dans ce format. Par exemple:Les fonctions explicites plus longues comme
to_int
,to_s
signifient que l'objet peut être représenté nativement comme ce type de données. Par exemple, laRational
classe représente tous les nombres rationnels, elle peut donc être directement représentée sous la forme d'un entier Fixnum (ou Bignum) en appelantto_int
.Si vous ne pouvez pas appeler la méthode plus longue, cela signifie que l'objet ne peut pas être représenté nativement dans ce type.
Donc, fondamentalement, lors de la conversion, si vous êtes paresseux avec les noms de méthode, Ruby sera paresseux avec la conversion.
la source
Depuis In Ruby, pourquoi ne pas
foo = true unless defined?(foo)
faire la mission?Parce que
foo
est défini commenil
quanddefined?(foo)
est appelé.la source
L'itération sur les hachages rubis n'est pas garantie dans un ordre particulier. (Ce n'est pas un bug, c'est une fonctionnalité)
Hash#sort
est utile si vous avez besoin d'une commande particulière.Question connexe: Pourquoi le tableau Ruby de 1000 paires de clés et de valeurs de hachage est-il toujours dans un ordre particulier?
la source
Celui-ci m'a rendu fou une fois:
la source
1/2
s'évalue à0
, ce qui n'est pas égal0.5
, quel que soit le type. CependantRational(1, 2) == 0.5
, et1.0 == 1
.ne fonctionne pas. Vous devez mettre la plage entre parenthèses, comme
donc il ne pense pas que vous appelez
5.each
. Je pense que c'est un problème de priorité, tout comme lex = true and false
gotcha.la source