Quels sont les Ruby Gotchas dont un débutant devrait être averti? [fermé]

108

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?

MiniQuark
la source
@ phrases.insert (0, p) OK @ phrases.insert (p) RIEN ne se passe @phrases << p # OK
Anno2001
pourquoi true and falseretourne vrai?
Jürgen Paul
3
Parce que "x = vrai et faux" est en fait interprété comme "(x = vrai) et faux". C'est une question de priorité des opérateurs: "et" a une priorité inférieure à "=". La plupart des autres langages ont la priorité inverse, je ne sais pas pourquoi ils ont choisi cet ordre dans Rails, je trouve cela très déroutant. Si vous voulez le comportement "normal", tapez simplement "x = (vrai et faux)", alors x sera faux.
MiniQuark
4
Une autre solution consiste à utiliser "&&" et "||" au lieu de "et" et "ou": ils se comportent comme prévu. Par exemple: "x = true && false" entraîne la valeur de x false.
MiniQuark
« Le principe de moindre surprise signifie principe du moins ma surprise. » from en.wikipedia.org/wiki/Ruby_(programming_language)#Philosophy Il en va de même pour Python. J'avais une citation similaire sur le créateur de Python mais j'oublie où il se trouvait.
Darek Nędza

Réponses:

59

Wikipédia Ruby gotchas

De l'article:

  • Les noms commençant par une majuscule sont traités comme des constantes, les variables locales doivent donc commencer par une lettre minuscule.
  • Les caractères $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.
  • Pour désigner des nombres à virgule flottante, il faut suivre avec un chiffre zéro ( 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.
  • Évaluation booléenne des données non-booléennes est stricte: 0, ""et []sont tous évalués à true. En C, l'expression est 0 ? 1 : 0évaluée à 0(c'est- à -dire faux). Dans Ruby, cependant, il cède 1, comme tous les nombres évaluent à true; seulement nilet falseévaluer false. 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, mais nilen cas d'échec (par exemple, incompatibilité). Cette convention est également utilisée dans Smalltalk, où seuls les objets spéciaux trueetfalse peuvent être utilisés dans une expression booléenne.
  • Les versions antérieures à 1.9 n'ont pas de type de données caractère (comparé à C, qui fournit un type charpour les caractères). Cela peut provoquer des surprises lors du découpage des chaînes: "abc"[0]yields 97(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 exemple do { statement } while (not(expression));en C / C ++ / ...), n'exécute jamais l'instruction si l'expression l'est déjà true. C'est parce que statement until expressionc'est en fait du sucre syntaxique sur

    until expression
      statement
    end

    , dont l'équivalent en C / C ++ est while (not(expression)) statement;comme statement if expressionest l'équivalent de

    if expression
      statement
    end

    Cependant, la notation

    begin
      statement
    end until expression

    dans Ruby exécutera en fait l'instruction une fois même si l'expression est déjà vraie.

  • Étant donné que les constantes sont des références à des objets, la modification de ce à quoi une constante fait référence génère un avertissement, mais la modification de l'objet lui-même ne le fait pas. Par exemple, Greeting << " world!" if Greeting == "Hello"ne génère pas d'erreur ni d'avertissement. Ceci est similaire aux finalvariables 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, andet or, ne suivent pas les règles normales de priorité: andne lie pas plus étroitement que or. Ruby a également des opérateurs d'expression ||et &&qui fonctionnent comme prévu.

  • defà l'intérieur defne fait pas ce à quoi un programmeur Python pourrait s'attendre:

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

    Cela donne une erreur de xne pas être défini. Vous devez utiliser un fichier Proc.

Caractéristiques linguistiques

  • L'omission de parenthèses autour des arguments de méthode peut conduire à des résultats inattendus si les méthodes acceptent plusieurs paramètres. Les développeurs de Ruby ont déclaré que l'omission de parenthèses sur les méthodes multi-paramètres pourrait être interdite dans les futures versions de Ruby; l'interpréteur Ruby actuel (novembre 2007) lance un avertissement qui encourage l'écrivain à ne pas omettre (), 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ée method_missing().
Andy
la source
1
Ruby 1.9 n'a pas non plus de type de données de caractère. Dans la version 1.8, l'opérateur d'index a renvoyé un Fixnum; dans 1.9, cela équivaut à découper une chaîne d'un caractère.
whitequark
38

Les débutants auront des problèmes avec les méthodes d'égalité :

  • a == b : vérifie si a et b sont égaux. C'est le plus utile.
  • a.eql? b : vérifie également si a et b sont égaux, mais c'est parfois plus strict (cela peut vérifier que a et b ont le même type, par exemple). Il est principalement utilisé dans les hachages.
  • a.égal? b : vérifie si a et b sont le même objet (contrôle d'identité).
  • a === b : utilisé dans les instructions case (je le lis comme " a correspond 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 é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:

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

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:

# === 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)

L' instruction case est basée sur la méthode === :

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

équivaut à 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 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:

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
2 tours
la source
1
Aussi: a = 'строка'; b = 'строка'; pa == b; a = a.Force_encoding 'ASCII-8BIT'; b = b.force_encoding 'UTF-8'; pa == b; pa === b; p a.eql? b; p a.égal? b
Nakilon
18

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

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

Cela imprime:

1
2 is even
3
4 is even
5

Mais si j'ajoute juste comment =quelque chose 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

Ensuite, je reçois:

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

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 à nilchaque 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:

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

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.

MiniQuark
la source
4
Vous pouvez tout aussi bien masquer la variable de portée extérieure par (1..5) do | number; comment | ..... Lire ici stackoverflow.com/questions/1654637/…
Özgür
6
Cela me semble logique. Cette portée est typique des autres langages, c'est juste la syntaxe qui est différente.
g.
Cependant, vous pouvez écrire a = (b if c)pour obtenir l'effet désiré, sans le ternaire. Ceci est dû b if cau cfait que la valeur est nulle si elle est fausse.
Cameron Martin
16

Lors d'un appel supersans argument, la méthode surchargée est en fait appelée avec les mêmes arguments que la méthode surchargée.

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 supersans argument, vous devez dire super().

Daniel Lucraft
la source
3
Si B#helloa name = 42avant le super, alors il dit "bonjour 42".
Andrew Grimm
14

Les blocs et les méthodes renvoient la valeur de la dernière ligne par défaut. L'ajout d' putsinstructions à la fin à des fins de débogage peut provoquer des effets secondaires désagréables

Andrew Grimm
la source
11

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:

class A
  @@classvar = "A1"
  @classattr = "A2"
  def self.showvars
    puts "@@classvar => "+@@classvar
    puts "@classattr => "+@classattr
  end
end

A.showvars
  # displays:
  # @@classvar => A1
  # @classattr => A2

class B < A
  @@classvar = "B1"
  @classattr = "B2"
end

B.showvars
  # displays:
  # @@classvar => B1
  # @classattr => B2

A.showvars
  # displays:
  # @@classvar => B1   #Class variables are shared in a class hierarchy!
  # @classattr => A2   #Class attributes are not
MiniQuark
la source
1
Oui, les variables de classe peuvent être délicates. Je pense que la plupart des rubisistes expérimentés diraient qu'il est sage de les éviter, car il existe généralement d'autres moyens de résoudre un problème sans eux. Certains passionnés de langage diraient même que les variables de classe de Ruby sont mal conçues au niveau du langage.
David J.
8

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.

Karina
la source
Vous pouvez utiliser a = b if a.nil?ou @a = b unless defined?(@a).
Andrew Grimm
8
  • 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.

dylanfm
la source
Si vous ne prévoyez pas d'aller au-delà de Ruby 1.8.6, ignorez les parens autant que vous le souhaitez. Sinon, vous feriez probablement mieux de les utiliser.
Mike Woodhouse
7

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:

module Displayable
  # instance methods here
  def display
    puts name
    self.class.increment_displays
  end
  def self.included(base)
    # This module method will be called automatically
    # after this module is included in a class.
    # We want to add the class methods to the class.
    base.extend Displayable::ClassMethods
  end
  module ClassMethods
    # class methods here
    def number_of_displays
      @number_of_displays # this is a class attribute
    end
    def increment_displays
      @number_of_displays += 1
    end
    def init_displays
      @number_of_displays = 0
    end
    # this module method will be called automatically
    # after this module is extended by a class.
    # We want to perform some initialization on a
    # class attribute.
    def self.extended(base)
      base.init_displays
    end
  end
end

class Person
  include Displayable
  def name; @name; end
  def initialize(name); @name=name; end
end

puts Person.number_of_displays # => 0
john = Person.new "John"
john.display # => John
puts Person.number_of_displays # => 1
jack = Person.new "Jack"
jack.display # => Jack
puts Person.number_of_displays # => 2

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:

module Displayable
  def display
    puts name
    self.class.increment_displays
  end
  def self.number_of_displays  # WRONG!
    @number_of_displays
  end
  [...]
end

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).

2 tours
la source
7

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:

  • facile à mal saisir, et
  • facile à rater des yeux en regardant le code

ne devrait pas être en mesure de provoquer des bogues dévastateurs dans mes programmes.

que que
la source
1
Pas très différent de for (i=0; i<max; i++)etfor (i=0; i<=max; i++)
g.
J'ai essayé de savoir quelle est la différence entre 0..10 et 0 ... 10.
Luis D Urraca
6

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_missingc'est vraiment plus comme message_not_understood.

some_object.do_something(args)

est équivalent à

some_object.send(:do_something, args) # note the :

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.

Mike Woodhouse
la source
Merci. Il y a une chose que je déteste à propos de la méthode send : elle vous permet d'appeler des méthodes privées même en dehors de la classe! Aie.
MiniQuark
1
@MiniQuark: c'est ce que j'aime dans la méthode d'envoi!
Andrew Grimm
6

Si vous déclarez un setter (aka mutator) en utilisant attr_writerou attr_accessor(ou def 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éthode self.foo=(bar).

class Thing
  attr_accessor :foo
  def initialize
    @foo = 1      # this sets @foo to 1
    self.foo = 2  # this sets @foo to 2
    foo = 3       # this does *not* set @foo
  end
end

puts Thing.new.foo #=> 2

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 = 123ou self['value'] = 123.

AlexChaffee
la source
5

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.

Chirantan
la source
4

Une chose qui m'a pris dans le passé est que la \nsé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.

John Topley
la source
1
Et c'est différent de quelle autre langue?
Robert Gamble
Java, pour un. Les guillemets simples en Java ne peuvent être utilisés que pour entourer un seul caractère, pas des chaînes.
John Topley
1
Ceci est conforme à tout langage qui vous permet d'utiliser des guillemets simples pour les chaînes, et c'est pourquoi ils le font.
singpolyma
@John: vrai, mais '\ n' en Java sera toujours le caractère de nouvelle ligne.
Jorn
1
Mais en Java, les guillemets simples ne créent que des valeurs de type char. Pas de chaînes. Voilà la différence.
jmucchiello
4
x = (true and false) # x is false

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.

singpolyma
la source
0 == true // argh le compilateur c dans mon cerveau explose !!
kenny
1
0 == true donne false en Ruby. Le fait que 0 soit vrai a du sens parce que vrai est un objet dans Ruby. En C 0 se trouve juste avoir la même représentation que false.
Jules
Dans une condition en Ruby, seuls falseet nilsont les faux. Tous les autres sont de vraies valeurs.
rubyprince
4

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! )

#demo.rb
class Demo

  def hello1
    p "Hello from first definition"
  end

  # ...lots of code here...
  # and you forget that you have already defined hello1

  def hello1
    p "Hello from second definition"
  end

end
Demo.new.hello1

Courir:

$ ruby demo.rb
=> "Hello from second definition"

Mais appelez-le avec les avertissements activés et vous pouvez voir la raison:

$ ruby -w demo.rb
demo.rb:10: warning: method redefined; discarding old hello1
=> "Hello from second definition"
Zabba
la source
J'aurais +100 l'utilisation d'avertissements si je le pouvais.
Andrew Grimm
3

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

Danmayer
la source
2

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.

irb(main):003:0* str_val = '5.0'
=> "5.0"
irb(main):006:0> str_val.to_int
NoMethodError: undefined method `to_int' for "5.0":String
        from (irb):6
irb(main):005:0* str_val.to_i
=> 5


irb(main):007:0> float_val = 5.0
=> 5.0
irb(main):008:0> float_val.to_int
=> 5
irb(main):009:0> float_val.to_i
=> 5
irb(main):010:0>

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.

Monkut
la source
2

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_sdites-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:

"10".to_i == 10
:foo.to_s == "foo"

Les fonctions explicites plus longues comme to_int, to_ssignifient que l'objet peut être représenté nativement comme ce type de données. Par exemple, la Rationalclasse représente tous les nombres rationnels, elle peut donc être directement représentée sous la forme d'un entier Fixnum (ou Bignum) en appelant to_int.

Rational(20,4).to_int == 5

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.

Luke
la source
1
Est-ce que «paresseux» est le mot juste ici?
Andrew Grimm du
1

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?

Andrew Grimm
la source
4
ceci n'est pas valide à partir de la version 1.9: "Dans Ruby 1.9, cependant, les éléments de hachage sont itérés dans leur ordre d'insertion" du Ruby Programming Language
Özgür
0

Celui-ci m'a rendu fou une fois:

1/2 == 0.5 #=> false
1/2 == 0   #=> true
Andrei
la source
Je pense que cela se comporterait exactement de la même manière en Java, C et C ++.
Larry
C'est drôle, je n'y ai même pas pensé, mais si vous ouvrez irb et essayez ceci, cela a du sens: donc (1/2) est un Fixnum et (0.5) est un Float. Et nous savons que Fixnim! = Float.
DemitryT
2
@DemitryT Je pense que la raison la plus simple est que 1/2s'évalue à 0, ce qui n'est pas égal 0.5, quel que soit le type. Cependant Rational(1, 2) == 0.5, et 1.0 == 1.
Max Nanasy
hoquet de langage universel ici. c'est quelque chose que quelqu'un de nouveau dans ruby ​​AND programmation devrait savoir.
dtc
0
1..5.each {|x| puts x}

ne fonctionne pas. Vous devez mettre la plage entre parenthèses, comme

(1..5).each {|x| puts x}

donc il ne pense pas que vous appelez 5.each. Je pense que c'est un problème de priorité, tout comme le x = true and falsegotcha.

Andrew Grimm
la source
Je l'appellerais plutôt parenthèse. Deuxièmement, si un code semble avoir un problème de valeur de retour / de priorité, il doit quand même être entouré de parenthèses. Donc, pour moi, il n'y a rien de spécial sur ce "gotcha". Vous pouvez continuer à écrire tous les "pièges" combinatoires, ce serait une perte de temps, cependant. Franchement mec, même si vous aviez le résultat escompté à ce sujet, je préférerais quand même l'entourer de parenthèses.
Özgür