Quali sono i Ruby Gotcha di cui un principiante dovrebbe essere avvisato? [chiuso]


108

Recentemente ho imparato il linguaggio di programmazione Ruby, e tutto sommato è un buon linguaggio. Ma sono rimasto piuttosto sorpreso di vedere che non era così semplice come mi aspettavo. Più precisamente, la "regola della minima sorpresa" non mi sembrava molto rispettata (ovviamente questo è abbastanza soggettivo). Per esempio:

x = true and false
puts x  # displays true!

e il famoso:

puts "zero is true!" if 0  # zero is true!

Quali sono gli altri "trucchi" di cui avvertiresti un principiante di Ruby?


@ phrases.insert (0, p) OK @ phrases.insert (p) NIENTE accade @phrases << p # OK
Anno2001

perché true and falseritorna vero?
Jürgen Paul

3
Perché "x = vero e falso" viene effettivamente interpretato come "(x = vero) e falso". È una questione di precedenza degli operatori: "e" ha una priorità inferiore a "=". La maggior parte delle altre lingue ha la priorità inversa, non so perché hanno scelto questo ordine in Rails, lo trovo molto confuso. Se vuoi il comportamento "normale", digita semplicemente "x = (vero e falso)", quindi x sarà falso.
MiniQuark

4
Un'altra soluzione è usare "&&" e "||" invece di "e" e "o": si comportano come previsto. Ad esempio: "x = true && false" risulta in x essere falso.
MiniQuark

“Il principio di minima sorpresa significa principio di almeno la mia sorpresa.” da en.wikipedia.org/wiki/Ruby_(programming_language)#Philosophy Lo stesso vale per Python. Avevo una citazione simile sul creatore di Python ma ho dimenticato dov'era.
Darek Nędza

Risposte:


59

Trucchi di Wikipedia su Ruby

Dall'articolo:

  • I nomi che iniziano con una lettera maiuscola sono trattati come costanti, quindi le variabili locali dovrebbero iniziare con una lettera minuscola.
  • I caratteri $e @non indicano il tipo di dati variabile come in Perl, ma funzionano piuttosto come operatori di risoluzione dell'ambito.
  • Per denotare numeri in virgola mobile, uno deve seguire con una cifra zero ( 99.0) o una conversione esplicita ( 99.to_f). Non è sufficiente aggiungere un punto ( 99.), perché i numeri sono suscettibili alla sintassi del metodo.
  • La valutazione booleana di dati non booleane è severo: 0, ""e []sono tutti valutati a true. In C, l'espressione 0 ? 1 : 0restituisce 0(cioè falso). In Ruby, tuttavia, produce 1, come tutti i numeri valutano true; solo nile falsevalutare false. Un corollario di questa regola è che i metodi Ruby per convenzione, ad esempio le ricerche di espressioni regolari, restituiscono numeri, stringhe, elenchi o altri valori non falsi in caso di successo, ma nilin caso di fallimento (ad esempio, mancata corrispondenza). Questa convenzione viene utilizzata anche in Smalltalk, dove solo gli oggetti speciali truee falsepossono essere utilizzati in un'espressione booleana.
  • Le versioni precedenti alla 1.9 non dispongono di un tipo di dati carattere (confronta con C, che fornisce il tipo charper i caratteri). Ciò può causare sorprese quando si tagliano le stringhe: "abc"[0]yields 97(un numero intero, che rappresenta il codice ASCII del primo carattere nella stringa); per ottenere l' "a"uso "abc"[0,1](una sottostringa di lunghezza 1) o "abc"[0].chr.
  • La notazione statement until expression, a differenza delle istruzioni equivalenti di altri linguaggi (ad esempio do { statement } while (not(expression));in C / C ++ / ...), in realtà non esegue mai l'istruzione se l'espressione è già true. Questo perché in statement until expressionrealtà è finito lo zucchero sintattico

    until expression
      statement
    end
    

    , l'equivalente di cui in C / C ++ è while (not(expression)) statement;proprio come statement if expressionè equivalente a

    if expression
      statement
    end
    

    Tuttavia, la notazione

    begin
      statement
    end until expression
    

    in Ruby infatti eseguirà l'istruzione una volta anche se l'espressione è già vera.

  • Poiché le costanti sono riferimenti a oggetti, la modifica di ciò a cui si riferisce una costante genera un avviso, ma la modifica dell'oggetto stesso non lo fa. Ad esempio, Greeting << " world!" if Greeting == "Hello"non genera un errore o un avviso. Questo è simile alle finalvariabili in Java, ma Ruby ha anche la funzionalità per "congelare" un oggetto, a differenza di Java.

Alcune caratteristiche che differiscono notevolmente da altre lingue:

  • I soliti operatori per le espressioni condizionali, ande or, non seguono le normali regole di precedenza: andnon si lega più strettamente di or. Ruby ha anche operatori di espressione ||e &&che funzionano come previsto.

  • definside defnon fa ciò che un programmatore Python potrebbe aspettarsi:

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

    Questo dà un errore di xnon essere definito. Devi usare un file Proc.

Caratteristiche del linguaggio

  • L'omissione di parentesi attorno agli argomenti del metodo può portare a risultati imprevisti se i metodi accettano più parametri. Gli sviluppatori di Ruby hanno affermato che l'omissione di parentesi sui metodi multiparametrici potrebbe essere disabilitata nelle future versioni di Ruby; l'attuale interprete Ruby (novembre 2007) lancia un avvertimento che incoraggia l'autore a non omettere (), per evitare ambigui significati del codice. Il non utilizzo ()è ancora una pratica comune e può essere particolarmente piacevole usare Ruby come linguaggio di programmazione specifico del dominio leggibile dall'uomo stesso, insieme al metodo chiamato method_missing().

1
Anche in Ruby 1.9 manca il tipo di dati carattere. In 1.8, l'operatore di indice ha restituito un Fixnum; in 1.9, equivale a tagliare una stringa di un carattere.
whitequark

38

I neofiti avranno problemi con i metodi di uguaglianza :

  • a == b : controlla se aeb sono uguali. Questa è la più utile.
  • a.eql? b : controlla anche se aeb sono uguali, ma a volte è più rigoroso (potrebbe controllare che aeb abbiano lo stesso tipo, per esempio). Viene utilizzato principalmente negli hash.
  • a.equal? b : verifica se aeb sono lo stesso oggetto (controllo identità).
  • a === b : usato nelle istruzioni case (l'ho letto come " a corrisponde a b ").

Questi esempi dovrebbero chiarire i primi 3 metodi:

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

Nota che == , eql? e uguale? dovrebbe essere sempre simmetrico: se a == b allora b == a.

Nota anche che == e eql? sono entrambi implementati nella classe Object come alias uguali? , quindi se crei una nuova classe e desideri == ed eql? per significare qualcos'altro oltre alla semplice identità, è necessario sovrascriverli entrambi. Per esempio:

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

Il metodo === si comporta in modo diverso. Prima di tutto è non simmetrico (a === b non non implica che b === a). Come ho detto, puoi leggere a === b come "a corrisponde a b". Ecco alcuni esempi:

# === 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' istruzione case si basa sul metodo === :

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

è equivalente a questo:

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

Se definisci una nuova classe le cui istanze rappresentano una sorta di contenitore o intervallo (se ha qualcosa come un metodo include? O match? ), Potresti trovare utile sovrascrivere il metodo === in questo modo:

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

1
Inoltre: 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. uguale? b
Nakilon


18

Il codice seguente mi ha sorpreso. Penso che sia un trucco pericoloso: sia facile da imbattersi che difficile da eseguire il debug.

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

Questo stampa:

1
2 is even
3
4 is even
5

Ma se aggiungo comment =qualcosa prima del blocco ...

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

Quindi ottengo:

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

Fondamentalmente, quando una variabile è definita solo all'interno di un blocco, viene distrutta alla fine del blocco e quindi viene ripristinata a nilogni iterazione. Di solito è quello che ti aspetti. Ma se la variabile è definita prima del blocco, la variabile esterna viene utilizzata all'interno del blocco e il suo valore è quindi persistente tra le iterazioni.

Una soluzione sarebbe scrivere questo invece:

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

Penso che molte persone (me compreso) tendano a scrivere " a = b if c" invece di " a = (c ? b : nil)", perché è più leggibile, ma ovviamente ha degli effetti collaterali.


4
Potresti anche ombreggiare la variabile di ambito esterno con (1..5) do | number; comment | ..... Leggi qui stackoverflow.com/questions/1654637/…
Özgür

6
Questo mi sembra logico. Questo scoping è tipico di altri linguaggi, è solo la sintassi che è diversa.
g.

Puoi comunque scrivere a = (b if c)per ottenere l'effetto desiderato, senza il ternario. Questo perché restituisce b if czero se cè falso.
Cameron Martin

16

Quando si chiama supersenza argomenti, il metodo sottoposto a override viene effettivamente chiamato con gli stessi argomenti del metodo override.

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"

Per chiamare effettivamente supersenza argomenti, devi dire super().


3
Se B#helloha name = 42prima di super, allora dice "ciao 42".
Andrew Grimm

14

Blocchi e metodi restituiscono il valore dell'ultima riga per impostazione predefinita. L'aggiunta di putsistruzioni alla fine per scopi di debug può causare spiacevoli effetti collaterali



11

Ho avuto molti problemi a capire le variabili di classe, gli attributi di classe e i metodi di classe. Questo codice potrebbe aiutare un principiante:

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

1
Sì, le variabili di classe possono essere complicate. Penso che i Rubyists più esperti direbbero che è saggio evitarli, poiché di solito ci sono altri modi per risolvere un problema senza di loro. Alcuni appassionati di lingue direbbero addirittura che le variabili di classe di Ruby sono mal progettate a livello linguistico.
David J.

8

una cosa che ho imparato è stata usare l'operatore || = con attenzione. e fai particolare attenzione se hai a che fare con valori booleani. Di solito usavo a || = b come catch all per dare a 'a' un valore predefinito se tutto il resto falliva e 'a' rimaneva zero. ma se a è falso eb è vero, allora a sarà assegnato vero.


Puoi usare a = b if a.nil?o @a = b unless defined?(@a).
Andrew Grimm

8
  • I blocchi sono molto importanti da capire, vengono usati ovunque.

  • Non hai bisogno di parentesi attorno ai parametri del metodo. Che tu li usi o meno dipende da te. Alcuni dicono che dovresti sempre usarli .

  • Usa rilancia e salva per gestire le eccezioni, non lancia e cattura.

  • Puoi usare ;ma non devi a meno che tu non voglia mettere più cose su una riga.


Se non hai intenzione di andare oltre Ruby 1.8.6, ignora i genitori quanto vuoi. Altrimenti, probabilmente faresti meglio a usarli.
Mike Woodhouse,

7

Ho avuto problemi con i mixin che contengono metodi di istanza e metodi di classe. Questo codice potrebbe aiutare un principiante:

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

All'inizio, pensavo di poter avere moduli con metodi di istanza e metodi di classe semplicemente facendo questo:

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

Sfortunatamente, il metodo number_of_displays non sarà mai incluso o esteso perché è un "metodo di classe modulo". Solo i "metodi di istanza del modulo" possono essere inclusi in una classe (come metodi di istanza) o estesi in una classe (come metodi di classe). Questo è il motivo per cui devi mettere i metodi di istanza del tuo mixin in un modulo e i metodi di classe del tuo mixin in un altro modulo (di solito metti i metodi di classe in un sottomodulo "ClassMethods"). Grazie al metodo magico incluso , puoi includere facilmente sia metodi di istanza che metodi di classe in una semplice chiamata "include Displayable" (come mostrato nell'esempio sopra).

Questo mixin conterà ogni display in base alla classe . Il contatore è un attributo di classe, quindi ogni classe avrà il suo (il tuo programma probabilmente fallirà se derivi una nuova classe dalla classe Person poiché il contatore @number_of_displays per la classe derivata non sarà mai inizializzato). Potresti voler sostituire @number_of_displays con @@ number_of_displays per renderlo un contatore globale. In questo caso, ogni gerarchia di classi avrà il proprio contatore. Se vuoi un contatore globale e unico, dovresti probabilmente renderlo un attributo del modulo.

Tutto questo non era decisamente intuitivo per me quando ho iniziato con Ruby.

Non riesco ancora a capire come rendere in modo pulito alcuni di questi metodi di mixin privati ​​o protetti (solo il metodo display e number_of_displays dovrebbe essere incluso come metodi pubblici).


7

Presta attenzione alla notazione Range.

(Almeno, prestare maggiore attenzione di quanto ho inizialmente fatto!)

C'è una differenza tra 0..10 (due punti) e 0...10(tre punti).

Ruby mi piace moltissimo. Ma questa cosa punto-punto contro punto-punto-punto mi infastidisce. Penso che una "caratteristica" a doppia sintassi così sottile sia:

  • facile da digitare in modo errato e
  • facile perdere con gli occhi mentre guardi il codice

non dovrebbe essere in grado di causare devastanti bug off-by-one nei miei programmi.


1
Non molto diverso da for (i=0; i<max; i++)efor (i=0; i<=max; i++)
g.

Ho cercato di scoprire qual è la differenza tra 0..10 e 0 ... 10.
Luis D Urraca

6

Penso che " and" e " or" siano un cenno a Perl, che è uno dei "genitori" più evidenti di Ruby (l'altro è Smalltalk). Entrambi hanno una precedenza molto più bassa (inferiore all'assegnazione, infatti, da cui proviene il comportamento annotato) rispetto a &&e ||quali sono gli operatori che dovresti usare.

Altre cose di cui essere consapevoli che non sono immediatamente ovvie:

Non chiami davvero metodi / funzioni, anche se sembra in questo modo. Invece, come in Smalltalk, invii un messaggio a un oggetto. Quindi method_missingè davvero più simile message_not_understood.

some_object.do_something(args)

è equivalente a

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

I simboli sono molto usati. Queste sono le cose con cui iniziano :e non sono immediatamente ovvie (beh non lo erano per me) ma prima le affronti meglio è.

Ruby è un grande esperto di "dattilografia", seguendo il principio che "se cammina come una papera e ciarlatano come un'anatra ..." che consente la sostituzione informale di oggetti con un sottoinsieme comune di metodi senza alcuna eredità esplicita o relazione di mixin.


Grazie. C'è una cosa che odio del metodo send : ti consente di chiamare metodi privati ​​anche al di fuori della classe! Ahia.
MiniQuark

1
@MiniQuark: questo è ciò che amo del metodo di invio!
Andrew Grimm

6

Se dichiari un setter (aka mutator) usando attr_writeror attr_accessor(or def foo=), fai attenzione a chiamarlo dall'interno della classe. Poiché le variabili sono dichiarate implicitamente, l'interprete deve sempre risolvere foo = bardichiarando una nuova variabile denominata foo, piuttosto che chiamare il metodo 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

Questo vale anche per gli oggetti Rails ActiveRecord, che ottengono le funzioni di accesso definite in base ai campi nel database. Poiché non sono nemmeno variabili di istanza stile @, il modo corretto per impostare questi valori individualmente è con self.value = 123o self['value'] = 123.


5

Capire la differenza tra le classi Time e Date. Entrambi sono diversi e hanno creato problemi durante il loro utilizzo nei binari. La classe Time a volte è in conflitto con altre librerie di classi Time presenti nella libreria standard ruby ​​/ rails. Personalmente mi ci è voluto molto tempo per capire cosa stesse succedendo esattamente nella mia app rails. Più tardi, ho capito quando l'ho fatto

Time.new

Si riferiva a qualche biblioteca in un luogo di cui non ero nemmeno a conoscenza.

Scusa se non sono chiaro con quello che voglio dire esattamente. Se altri hanno riscontrato problemi simili, si prega di spiegare nuovamente.


4

Uno che mi ha colpito in passato è che la \nsequenza di escape del carattere di nuova riga ( ), tra le altre, non è supportata da stringhe all'interno di virgolette singole. Il backslash stesso viene eliminato. È necessario utilizzare le virgolette doppie affinché l'escape funzioni come previsto.


1
E questo è diverso da quale altra lingua?
Robert Gamble

Java, per esempio. Le virgolette singole in Java possono essere utilizzate solo per racchiudere un singolo carattere, non stringhe.
John Topley

1
Questo è in armonia con qualsiasi linguaggio che ti consente di utilizzare virgolette singole per le stringhe, ed è per questo che lo fanno.
singpolyma

@ John: vero, ma "\ n" in Java sarà ancora il carattere di nuova riga.
Jorn

1
Ma in Java le virgolette singole creano solo valori di tipo char. Non stringhe. Questa è la differenza.
jmucchiello

4
x = (true and false) # x is false

0 e '' sono veri, come hai sottolineato.

Puoi avere un metodo e un modulo / classe con lo stesso nome (il che ha senso, perché il metodo viene effettivamente aggiunto a Object e quindi ha il proprio spazio dei nomi).

Non esiste un'ereditarietà multipla, ma spesso vengono usati "moduli mixin" per aggiungere metodi comuni a più classi.


0 == true // argh il compilatore c nel mio cervello sta esplodendo !!
kenny

1
0 == true restituisce false in Ruby. Che 0 sia vero ha senso perché vero è un oggetto in Ruby. In C 0 accade solo di avere la stessa rappresentazione di false.
Jules

In una condizione in Ruby, solo falsee nilsono i falsi. Tutti gli altri sono veri valori.
rubyprince

4

I metodi possono essere ridefiniti e possono diventare un graffio mentale fino a quando non si scopre la causa. ( Certo, questo errore è probabilmente un po 'più "difficile" da rilevare quando l'azione di un controller Ruby on Rails viene ridefinita per errore! )

#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

Correre:

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

Ma chiamalo con gli avvisi abilitati e puoi vedere il motivo:

$ ruby -w demo.rb
demo.rb:10: warning: method redefined; discarding old hello1
=> "Hello from second definition"

Se potessi, avrei +100 l'uso degli avvisi.
Andrew Grimm

3

Penso che sia sempre bene usare .length sulle cose ... poiché la dimensione è supportata da quasi tutto e Ruby ha tipi dinamici, puoi ottenere risultati davvero strani chiamando .size quando hai il tipo sbagliato ... Preferirei di gran lunga ottenere a NoMethodError: undefined metodo `length ', quindi generalmente non chiamo mai size sugli oggetti in Ruby.

mi ha morso più di una volta.

Ricorda anche che gli oggetti hanno id, quindi cerco di non usare le variabili call id o object_id solo per evitare confusione. Se ho bisogno di un id su un oggetto Users, è meglio chiamarlo qualcosa come user_id.

Solo i miei due centesimi


2

Sono nuovo in ruby ​​e al mio primo round ho riscontrato un problema riguardante la modifica di float / stringhe in un numero intero. Ho iniziato con i float e ho codificato tutto come f.to_int . Ma quando ho continuato e ho utilizzato lo stesso metodo per le stringhe, quando si è trattato di eseguire il programma, mi è stata fatta una curva.

A quanto pare una stringa non ha un metodo to_int , ma float e int .

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>

Anche le parentesi arbitrarie all'inizio mi hanno sconcertato. Ho visto del codice con e altri senza. Mi ci è voluto un po 'per capire che entrambi gli stili sono accettati.


2

In relazione alla risposta di monkut, i to_foometodi di Ruby suggeriscono quanto rigorosa sarà la conversione.

Quelli brevi come to_i, to_sdigli di essere pigro e convertili nel tipo di destinazione anche se non possono essere rappresentati accuratamente in quel formato. Per esempio:

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

Le funzioni esplicite più lunghe come to_int, to_ssignificano che l'oggetto può essere rappresentato in modo nativo come quel tipo di dati. Ad esempio, la Rationalclasse rappresenta tutti i numeri razionali, quindi può essere rappresentata direttamente come un numero intero Fixnum (o Bignum) chiamando to_int.

Rational(20,4).to_int == 5

Se non puoi chiamare il metodo più lungo, significa che l'oggetto non può essere rappresentato in modo nativo in quel tipo.

Quindi, in pratica, durante la conversione, se sei pigro con i nomi dei metodi, Ruby sarà pigro con la conversione.


1
"Pigro" è la parola giusta qui?
Andrew Grimm


1

Non è garantito che l'iterazione sugli hash Ruby avvenga in un ordine particolare. (Non è un bug, è una caratteristica)

Hash#sort è utile se hai bisogno di un ordine particolare.

Domanda correlata: Perché l'array di Ruby di 1000 coppie di chiavi e valori di hash è sempre in un ordine particolare?


4
questo non è valido a partire da 1.9: "In Ruby 1.9, tuttavia, gli elementi hash sono iterati nel loro ordine di inserzione" dal Linguaggio di programmazione Ruby
Özgür

0

Questo mi ha fatto impazzire una volta:

1/2 == 0.5 #=> false
1/2 == 0   #=> true

Credo che questo si comporterebbe esattamente allo stesso modo in Java, C e C ++.
Larry

È divertente, non ci ho nemmeno pensato, ma se apri irb e provi questo, ha senso: quindi (1/2) è un Fixnum e (0.5) è un Float. E sappiamo che Fixnim! = Float.
DemitryT

2
@DemitryT Penso che la ragione più semplice è che 1/2restituisce 0, che non è uguale 0.5, indipendentemente dal tipo. Tuttavia Rational(1, 2) == 0.5, e 1.0 == 1.
Max Nanasy

singhiozzo del linguaggio universale qui. questo è qualcosa che qualcuno di nuovo a Ruby E alla programmazione dovrebbe sapere.
dtc

0
1..5.each {|x| puts x}

non funziona. Devi mettere l'intervallo tra parentesi, tipo

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

quindi non pensa che tu stia chiamando 5.each. Penso che questo sia un problema di precedenza, proprio come il x = true and falsegotcha.


La chiamerei invece parentesi. In secondo luogo, se un codice sembra avere un valore di ritorno / un problema di precedenza, dovrebbe comunque essere racchiuso tra parentesi. Quindi, per me, non c'è niente di speciale in questo "gotcha". Puoi continuare a scrivere tutti i "trucchi" combinatori, ma sarebbe una perdita di tempo. Francamente amico, anche se avessi il risultato atteso su questo, preferirei comunque circondare tra parentesi.
Özgür
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.