108 votes

Quels sont les pièges de Ruby un débutant devrait être averti ?

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 prévu. Plus précisément, la "règle de la moindre surprise" ne me semblait pas très respectée (bien sûr, cela 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" que vous avertiriez un débutant Ruby?

59voto

Andy Points 3471

Wikipédia Ruby pièges

De l'article:

  • Les noms qui commencent par une lettre majuscule sont traités comme des constantes, de sorte que les variables locales doivent commencer par une lettre minuscule.
  • Les personnages $ et @ n'indiquent pas le type de données de variable comme en Perl, mais plutôt en fonction de résolution de portée des opérateurs.
  • Pour désigner les nombres à virgule flottante, on doit suivre avec un chiffre zéro (99.0) ou une conversion explicite (99.to_f). C'est insuffisant pour ajouter un point (99.), parce que les nombres sont sensibles à la méthode de la syntaxe.
  • Boolean évaluation de la non-booléenne de données est stricte: 0, "" et [] sont toutes évaluées à l' true. En C, l'expression 0 ? 1 : 0 évalue 0 (faux). En Ruby, cependant, il donne des 1, comme tous les numéros d'évaluer à l' true; seulement nil et false évaluer à l' false. Un corollaire de cette règle est que les méthodes Ruby par la convention - par exemple, l'expression régulière recherches - retour nombres, chaînes de caractères, listes, ou d'autres non-fausses valeurs sur le succès, mais nil en cas d'échec (par exemple, l'inadéquation). Cette convention est également utilisé dans Smalltalk, où seuls les objets spéciaux true et false peut être utilisé dans une expression booléenne.
  • Les Versions antérieures à 1,9 manque un type de données caractère (à comparer avec le C, qui fournit de type char pour les personnages). Cela peut causer des surprises pour le découpage de chaînes de caractères: "abc"[0] rendements en 97 (un entier, qui représente le code ASCII du premier caractère de la chaîne); pour obtenir de l' "a" utilisation "abc"[0,1] (une sous-chaîne de longueur 1) ou "abc"[0].chr.
  • La notation statement until expression, contrairement à d'autres langues " instructions équivalentes (par exemple, do { statement } while (not(expression)); en C/C++/...), en fait n'est jamais à la déclaration, si l'expression est déjà true. C'est parce qu' statement until expression est effectivement sucre syntaxique plus

    until expression
      statement
    end
    

    l'équivalent de ce qui en C/C++ est - while (not(expression)) statement; comme statement if expression est équivalente à

    if expression
      statement
    end
    

    Cependant, la notation

    begin
      statement
    end until expression
    

    Ruby va, en fait, exécutez l'instruction une fois, même si l'expression est déjà le cas.

  • Parce que les constantes sont des références à des objets, de transformer ce qui est une constante désigne génère un avertissement, mais la modification de l'objet lui-même ne l'est pas. Par exemple, Greeting << " world!" if Greeting == "Hello" ne génère pas une erreur ou un avertissement. Ceci est similaire à l' final variables en Java, mais Ruby ne aussi la fonctionnalité de "geler" un objet, contrairement à Java.

- Unes des caractéristiques qui diffèrent notamment à partir d'autres langues:

  • L'habitude des opérateurs pour les expressions conditionnelles, and et or, ne suivez pas les règles normales de priorité: and ne se lie pas plus serré que l' or. Ruby a aussi des opérateurs d'expression || et && qui fonctionnent comme prévu.

  • def à l'intérieur d' def ne pas faire ce qu'un programmeur Python pourrait s'attendre:

    def a_method
        x = 7
        def print_x; puts x end
        print_x
    end
    

    Cela donne une erreur à propos de x n'est pas définie. Vous devez utiliser un Proc.

Fonctionnalités de la langue

  • Omission de parenthèses autour des arguments de méthode peut entraîner des résultats inattendus si les méthodes prennent de multiples paramètres. Les développeurs Ruby ont déclaré que l'omission de parenthèses sur multi-paramètre des méthodes peut être refusée dans les futures versions Rubis; le courant (novembre 2007) interpréteur Ruby lance un avertissement qui encourage l'écrivain de ne pas omettre (), pour éviter l'ambiguïté de code. Ne pas utiliser () est encore une pratique courante, et peut être particulièrement agréable à utiliser Ruby comme lisible par un humain spécifique au domaine du langage de programmation lui-même, avec la méthode dite method_missing().

38voto

MiniQuark Points 8927

Les débutants auront du mal avec l'égalité méthodes:

  • a == b : vérifie si a et b sont égaux. C'est le plus utile.
  • un.eql? b : vérifie également si a et b sont égaux, mais il est parfois plus strictes (il peut vérifier que a et b ont le même type, par exemple). Il est principalement utilisé dans les tables de hachage.
  • un.l'égalité? b : vérifie si a et b sont de la même objet (contrôle d'identité).
  • a === b : utilisé dans le cas des énoncés (je l'ai lu comme "un des matchs b").

Ces exemples devraient clarifier les 3 premières méthodes:

a = b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # true (a.object_id == b.object_id)

a = "joe"
b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # false (a.object_id != b.object_id)

a = 1
b = 1.0

a==b       # true
a.eql? b   # false (a.class != b.class)
a.equal? b # false

Notez que ==, eql? et l'égalité? doit toujours être symétrique : si a==b alors b==.

Notez aussi que l' == et eql? sont mis en œuvre dans la classe de l'Objet en tant qu'alias de l'égalité?, donc, si vous créez une nouvelle classe et souhaitez == et eql? pour dire autre chose que la simple identité, alors vous avez besoin de les remplacer à la fois. Par exemple:

class Person
    attr_reader name
    def == (rhs)
      rhs.name == self.name  # compare person by their name
    end
    def eql? (rhs)
      self == rhs
    end
    # never override the equal? method!
end

L' === méthode se comporte différemment. Tout d'abord, il n'est pas symétrique (a===b n'a pas implique que b===un). Comme je l'ai dit, vous pouvez lire un===b "correspond à un b". Voici quelques exemples:

# === is usually simply an alias for ==
"joe" === "joe"  # true
"joe" === "bob"  # false

# but ranges match any value they include
(1..10) === 5        # true
(1..10) === 19       # false
(1..10) === (1..10)  # false (the range does not include itself)

# arrays just match equal arrays, but they do not match included values!
[1,2,3] === [1,2,3] # true
[1,2,3] === 2       # false

# classes match their instances and instances of derived classes
String === "joe"   # true
String === 1.5     # false (1.5 is not a String)
String === String  # false (the String class is not itself a String)

Le cas affirmation est basée sur l' === méthode:

case a
  when "joe": puts "1"
  when 1.0  : puts "2"
  when (1..10), (15..20): puts "3"
  else puts "4"
end

est équivalent à ceci:

if "joe" === a
  puts "1"
elsif 1.0 === a
  puts "2"
elsif (1..10) === a || (15..20) === a
  puts "3"
else
  puts "4"
end

Si vous définissez une nouvelle classe dont les instances représentent une sorte de conteneur ou de la plage (si il a quelque chose comme un ? ou un match? méthode), alors vous trouverez peut-être utile pour remplacer l' === méthode comme ceci:

class Subnet
  [...]
  def include? (ip_address_or_subnet)
    [...]
  end
  def === (rhs)
    self.include? rhs
  end
end

case destination_ip
  when white_listed_subnet: puts "the ip belongs to the white-listed subnet"
  when black_listed_subnet: puts "the ip belongs to the black-listed subnet"
  [...]
end

20voto

Dan Vinton Points 11975
  • Monkey patching. Ruby a l'ouverture des classes, de sorte que leur comportement peut être changé dynamiquement lors de l'exécution...

  • Des objets pourrait répondre à pas défini des méthodes de si method_missing ou send a été remplacé. Cela permet d'exploiter Ruby est basé sur le message d'invocation de méthode. Rails' ActiveRecord système utilise ce à grand effet.

18voto

MiniQuark Points 8927

Le code suivant m'a surpris. Je pense que c'est un dangereux piège: à la fois facile à exécuter, et difficiles à déboguer.

(1..5).each do |number|
  comment = " is even" if number%2==0
  puts number.to_s + comment.to_s
end

Cette affiche:

1
2 is even
3
4 is even
5

Mais si je viens de l'ajouter comment =rien avant le bloc...

comment = nil
(1..5).each do |number|
  comment = " is even" if number%2==0
  puts number.to_s + comment.to_s
end

Puis-je obtenir:

1
2 is even
3 is even
4 is even
5 is even

En gros, quand une variable n'est définie à l'intérieur d'un bloc, puis il est détruit à la fin du bloc, puis il est remis à l' nil lors de chaque itération. C'est habituellement ce que vous attendez. Mais si la variable est définie avant le bloc, alors que l'extérieur de la variable est utilisée à l'intérieur du bloc, et sa valeur est donc persistant entre les itérations.

Une solution serait d'écrire ceci à la place:

comment = number%2==0 ? " is even" : nil

Je pense que beaucoup de gens (dont moi) ont tendance à écrire "a = b if c" au lieu de "a = (c ? b : nil)", parce que c'est plus lisible, mais, évidemment, il a des effets secondaires.

16voto

Daniel Lucraft Points 3323

Lorsque vous appelez super sans arguments, la méthode surchargée est en fait appelée avec les mêmes arguments que la méthode de substitution.

 class A
  def hello(name="Dan")
    puts "hello #{name}"
  end
end

class B < A
  def hello(name)
    super
  end
end

B.new.hello("Bob") #=> "hello Bob"
 

Pour appeler réellement super sans arguments, vous devez dire super() .

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