Apa Ruby Gotcha yang harus diperingatkan oleh seorang pemula? [Tutup]

108

Saya baru-baru ini belajar bahasa pemrograman Ruby, dan secara keseluruhan itu adalah bahasa yang bagus. Tetapi saya cukup terkejut melihat bahwa itu tidak sesederhana yang saya harapkan. Lebih tepatnya, "aturan yang paling tidak mengejutkan" tampaknya tidak terlalu dihargai bagi saya (tentu saja ini sangat subjektif). Sebagai contoh:

x = true and false
puts x  # displays true!

dan yang terkenal:

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

Apa "Gotcha" lain yang akan Anda peringatkan untuk pemula Ruby?

MiniQuark
sumber
@ phrases.insert (0, p) OK @ phrases.insert (p) TIDAK ADA yang terjadi @phrases << p # OK
Anno2001
mengapa true and falsekembali benar?
Jürgen Paul
3
Karena "x = true dan false" sebenarnya diartikan sebagai "(x = true) dan false". Ini masalah prioritas operator: "dan" memiliki prioritas lebih rendah daripada "=". Sebagian besar bahasa lain memiliki prioritas terbalik, saya tidak tahu mengapa mereka memilih urutan ini di Rails, saya merasa sangat membingungkan. Jika Anda menginginkan perilaku "normal", cukup ketik "x = (benar dan salah)", maka x akan salah.
MiniQuark
4
Solusi lain adalah menggunakan "&&" dan "||" bukannya "dan" dan "atau": keduanya berperilaku seperti yang diharapkan. Misalnya: "x = true && false" menghasilkan x menjadi salah.
MiniQuark
"Prinsip paling tidak mengejutkan berarti prinsip paling tidak kejutan saya ." dari en.wikipedia.org/wiki/Ruby_(programming_language)#Philosophy Hal yang sama berlaku untuk Python. Saya memiliki kutipan serupa tentang pembuat Python tetapi saya lupa di mana itu.
Darek Nędza

Jawaban:

59

Wikipedia Ruby gotchas

Dari artikel:

  • Nama yang dimulai dengan huruf kapital diperlakukan sebagai konstanta, jadi variabel lokal harus dimulai dengan huruf kecil.
  • Karakter $dan @tidak menunjukkan tipe data variabel seperti di Perl, melainkan berfungsi sebagai operator resolusi cakupan.
  • Untuk menunjukkan angka floating point, seseorang harus mengikuti dengan digit nol ( 99.0) atau konversi eksplisit ( 99.to_f). Tidak cukup menambahkan titik ( 99.), karena angka rentan terhadap sintaks metode.
  • Evaluasi Boolean data non-boolean ketat: 0, ""dan []semua dievaluasi untuk true. Dalam C, ekspresi 0 ? 1 : 0mengevaluasi ke 0(yaitu salah). Di Ruby, bagaimanapun, itu menghasilkan 1, karena semua angka mengevaluasi true; hanya nildan falseevaluasi ke false. Akibat wajar dari aturan ini adalah bahwa metode Ruby berdasarkan konvensi - misalnya, pencarian ekspresi reguler - mengembalikan angka, string, daftar, atau nilai non-salah lainnya pada keberhasilan, tetapi nilpada kegagalan (misalnya, ketidakcocokan). Konvensi ini juga digunakan di Smalltalk, di mana hanya objek khusus truedan falsedapat digunakan dalam ekspresi boolean.
  • Versi sebelum 1.9 tidak memiliki tipe data karakter (bandingkan dengan C, yang menyediakan tipe charuntuk karakter). Hal ini dapat menyebabkan kejutan saat memotong string: "abc"[0]hasil 97(bilangan bulat, mewakili kode ASCII dari karakter pertama dalam string); untuk mendapatkan "a"penggunaan "abc"[0,1](substring dengan panjang 1) atau "abc"[0].chr.
  • Notasi statement until expression, tidak seperti pernyataan padanan bahasa lain (misalnya do { statement } while (not(expression));dalam C / C ++ / ...), sebenarnya tidak pernah menjalankan pernyataan jika ekspresi sudah ada true. Ini karena statement until expressionsebenarnya gula sintaksis sudah berakhir

    until expression
      statement
    end
    

    , padanannya dalam C / C ++ sama while (not(expression)) statement;saja statement if expressiondengan

    if expression
      statement
    end
    

    Namun, notasinya

    begin
      statement
    end until expression
    

    di Ruby sebenarnya akan menjalankan pernyataan satu kali bahkan jika ekspresi tersebut sudah benar.

  • Karena konstanta adalah referensi ke objek, mengubah apa yang dirujuk oleh konstanta menghasilkan peringatan, tetapi memodifikasi objek itu sendiri tidak. Misalnya, Greeting << " world!" if Greeting == "Hello"tidak menghasilkan kesalahan atau peringatan. Ini mirip dengan finalvariabel di Java, tetapi Ruby juga memiliki fungsionalitas untuk "membekukan" objek, tidak seperti Java.

Beberapa fitur yang sangat berbeda dari bahasa lain:

  • Operator biasa untuk ekspresi bersyarat, anddan or, jangan mengikuti aturan normal yang diutamakan: andtidak mengikat lebih dari or. Ruby juga memiliki operator ekspresi ||dan &&berfungsi seperti yang diharapkan.

  • defdi dalamnya deftidak melakukan apa yang diharapkan programmer Python:

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

    Ini memberikan kesalahan tentang xtidak didefinisikan. Anda perlu menggunakan file Proc.

Fitur bahasa

  • Penghilangan tanda kurung di sekitar argumen metode dapat menyebabkan hasil yang tidak diharapkan jika metode tersebut mengambil beberapa parameter. Pengembang Ruby telah menyatakan bahwa penghilangan tanda kurung pada metode multi-parameter mungkin tidak diizinkan di versi Ruby yang akan datang; interpreter Ruby saat ini (November 2007) mengeluarkan peringatan yang mendorong penulis untuk tidak menghilangkan (), untuk menghindari makna kode yang ambigu. Tidak menggunakan ()masih merupakan praktik umum, dan bisa sangat menyenangkan untuk menggunakan Ruby sebagai bahasa pemrograman khusus domain yang dapat dibaca manusia itu sendiri, bersama dengan metode yang dipanggil method_missing().
Andy
sumber
1
Ruby 1.9 juga tidak memiliki tipe data karakter. Di 1.8, operator indeks mengembalikan Fixnum; di 1.9, ini setara dengan memotong string satu karakter.
whitequark
38

Pemula akan mengalami masalah dengan metode kesetaraan :

  • a == b : memeriksa apakah a dan b sama. Ini yang paling berguna.
  • a.eql? b : juga memeriksa apakah a dan b sama, tetapi terkadang lebih ketat (mungkin memeriksa bahwa a dan b memiliki tipe yang sama, misalnya). Ini terutama digunakan di Hashes.
  • a.equal? b : memeriksa apakah a dan b adalah objek yang sama (pemeriksaan identitas).
  • a === b : digunakan dalam pernyataan kasus (saya membacanya sebagai " a pertandingan b ").

Contoh berikut seharusnya menjelaskan 3 metode pertama:

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

Perhatikan bahwa == , eql? dan setara? harus selalu simetris: jika a == b maka b == a.

Perhatikan juga bahwa == dan eql? keduanya diimplementasikan di kelas Object sebagai alias sama? , jadi jika Anda membuat kelas baru dan ingin == dan eql? untuk mengartikan sesuatu selain identitas biasa, maka Anda harus mengesampingkan keduanya. Sebagai contoh:

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

The === Metode berperilaku berbeda. Pertama-tama ini tidak simetris (a === b tidak berarti bahwa b === a). Seperti yang saya katakan, Anda bisa membaca a === b sebagai "a korek api b". Berikut beberapa contoh:

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

The kasus Pernyataan ini didasarkan pada === metode:

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

setara dengan ini:

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

Jika Anda mendefinisikan kelas baru yang instansinya mewakili semacam wadah atau rentang (jika memiliki sesuatu seperti metode include? Atau cocok? ), Anda mungkin merasa berguna untuk mengganti metode === seperti ini:

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
MiniQuark
sumber
1
Juga: 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.equal? b
Nakilon
18

Kode berikut mengejutkan saya. Saya pikir itu adalah gotcha yang berbahaya: mudah ditemui, dan sulit untuk di-debug.

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

Ini mencetak:

1
2 is even
3
4 is even
5

Tetapi jika saya menambahkan comment =apa pun sebelum blok ...

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

Kemudian saya mendapatkan:

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

Pada dasarnya, ketika sebuah variabel hanya didefinisikan di dalam sebuah blok, maka ia dihancurkan di akhir blok, dan kemudian direset ke nilsetiap iterasi. Biasanya itulah yang Anda harapkan. Tetapi jika variabel yang didefinisikan sebelum blok, maka variabel luar yang digunakan di dalam blok, dan nilainya karena itu terus-menerus antara iterasi.

Salah satu solusinya adalah menulis ini sebagai gantinya:

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

Saya rasa banyak orang (termasuk saya) cenderung menulis " a = b if c" daripada " a = (c ? b : nil)", karena lebih mudah dibaca, tetapi jelas memiliki efek samping.

MiniQuark
sumber
4
Anda mungkin juga membayangi variabel lingkup luar dengan (1..5) do | number; comment | ..... Baca di sini stackoverflow.com/questions/1654637/…
Özgür
6
Ini sepertinya logis bagi saya. Cakupan ini khas dari bahasa lain, hanya sintaksnya yang berbeda.
g.
Namun, Anda dapat menulis a = (b if c)untuk mendapatkan efek yang diinginkan, tanpa terner. Ini karena b if cmengevaluasi ke nihil jika csalah.
Cameron Martin
16

Saat memanggil supertanpa argumen, metode yang ditimpa sebenarnya dipanggil dengan argumen yang sama dengan metode penggantian.

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"

Untuk benar-benar menelepon supertanpa argumen, Anda perlu mengatakannya super().

Daniel Lucraft
sumber
3
Jika B#hellomemiliki name = 42sebelum super, maka dikatakan "halo 42".
Andrew Grimm
14

Blok dan metode mengembalikan nilai baris terakhir secara default. Menambahkan putspernyataan di akhir untuk tujuan debugging dapat menyebabkan efek samping yang tidak menyenangkan

Andrew Grimm
sumber
11

Saya mengalami banyak kesulitan dalam memahami variabel kelas, atribut kelas, dan metode kelas. Kode ini mungkin membantu pemula:

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
sumber
1
Ya, variabel kelas bisa jadi rumit. Saya rasa Rubyist yang paling berpengalaman akan mengatakan bahwa bijaksana untuk menghindarinya, karena biasanya ada cara lain untuk menyelesaikan masalah tanpa mereka. Beberapa penggemar bahasa bahkan akan mengatakan bahwa variabel kelas Ruby dirancang dengan buruk pada tingkat bahasa.
David J.
8

satu hal yang saya pelajari adalah menggunakan operator || = dengan hati-hati. dan berhati-hatilah jika Anda berurusan dengan boolean. saya biasanya menggunakan a || = b sebagai tangkapan semua untuk memberikan 'a' nilai default jika semuanya gagal dan 'a' tetap nihil. tetapi jika a salah dan b benar, maka a akan diberikan benar.

karina
sumber
Anda dapat menggunakan a = b if a.nil?atau @a = b unless defined?(@a).
Andrew Grimm
8
  • Blok sangat penting untuk dipahami, mereka digunakan di mana-mana.

  • Anda tidak perlu tanda kurung di sekitar parameter metode. Apakah Anda menggunakannya atau tidak, itu terserah Anda. Beberapa orang mengatakan Anda harus selalu menggunakannya .

  • Gunakan peningkatan dan penyelamatan untuk penanganan pengecualian, bukan melempar dan menangkap.

  • Anda dapat menggunakan ;tetapi Anda tidak harus melakukannya kecuali Anda ingin meletakkan banyak hal dalam satu baris.

dylanfm
sumber
Jika Anda tidak berencana untuk melampaui Ruby 1.8.6 maka abaikan parens sebanyak yang Anda suka. Jika tidak, Anda mungkin lebih baik menggunakannya.
Mike Woodhouse
7

Saya mengalami masalah dengan mixin yang berisi metode instance dan metode kelas. Kode ini mungkin membantu pemula:

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

Pada awalnya, saya pikir saya dapat memiliki modul dengan metode instance dan metode kelas hanya dengan melakukan ini:

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

Sayangnya, metode number_of_displays tidak akan pernah disertakan atau diperpanjang karena ini adalah "metode kelas modul". Hanya "metode instance modul" yang dapat dimasukkan ke dalam kelas (sebagai metode instance) atau diperluas ke dalam kelas (sebagai metode kelas). Inilah sebabnya mengapa Anda perlu menempatkan metode instance mixin Anda ke dalam modul, dan metode kelas mixin Anda ke dalam modul lain (Anda biasanya meletakkan metode kelas ke dalam submodul "ClassMethods"). Berkat metode ajaib yang disertakan , Anda dapat membuatnya mudah untuk menyertakan kedua metode instance dan metode kelas hanya dalam satu panggilan sederhana "sertakan Displ dapat" (seperti yang ditunjukkan pada contoh di atas).

Mixin ini akan menghitung setiap tampilan per kelas . Penghitung adalah atribut kelas, jadi setiap kelas akan memiliki sendiri (program Anda mungkin akan gagal jika Anda mendapatkan kelas baru dari kelas Person karena penghitung @number_of_displays untuk kelas turunan tidak akan pernah diinisialisasi). Anda mungkin ingin mengganti @number_of_displays dengan @@ number_of_displays untuk menjadikannya counter global. Dalam hal ini, setiap hierarki kelas akan memiliki penghitungnya sendiri. Jika Anda menginginkan penghitung global dan unik, Anda mungkin harus menjadikannya sebagai atribut modul.

Semua ini jelas tidak intuitif bagi saya ketika saya mulai menggunakan Ruby.

Saya masih tidak tahu cara membuat beberapa metode mixin ini pribadi atau dilindungi dengan bersih (hanya metode display dan number_of_displays yang harus dimasukkan sebagai metode publik).

MiniQuark
sumber
7

Perhatikan notasi Range.

(Setidaknya, lebih perhatikan daripada yang saya lakukan pada awalnya!)

Ada perbedaan antara 0..10 (dua titik) dan 0...10(tiga titik).

Saya sangat menikmati Ruby. Tetapi hal titik-titik versus titik-titik-titik ini mengganggu saya. Menurut saya, "fitur" sintaks ganda yang begitu halus adalah:

  • mudah salah ketik, dan
  • mudah terlewatkan saat melihat kode

seharusnya tidak dapat menyebabkan bug yang menghancurkan satu per satu dalam program saya.

que que
sumber
1
Tidak jauh berbeda dengan for (i=0; i<max; i++)danfor (i=0; i<=max; i++)
g.
Saya mencoba untuk mencari tahu apa perbedaan antara 0..10 dan 0 ... 10.
Luis D Urraca
6

Saya pikir " and" dan " or" adalah anggukan untuk Perl, yang merupakan salah satu "orang tua" Ruby yang lebih jelas (yang paling menonjol adalah Smalltalk). Keduanya memiliki prioritas yang jauh lebih rendah (sebenarnya lebih rendah dari penugasan, dari sanalah asal perilaku yang dicatat) daripada &&dan ||operator mana yang harus Anda gunakan.

Hal-hal lain yang harus diperhatikan yang tidak segera terlihat:

Anda tidak benar-benar memanggil metode / fungsi, meskipun kelihatannya seperti itu. Sebaliknya, seperti di Smalltalk, Anda mengirim pesan ke suatu objek. Jadi method_missingbenar-benar lebih seperti message_not_understood.

some_object.do_something(args)

setara dengan

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

Simbol sangat banyak digunakan. Itulah hal-hal yang dimulai :dan tidak segera terlihat (yah, itu tidak bagi saya) tetapi semakin awal Anda mengatasinya semakin baik.

Ruby sangat ahli dalam "mengetik bebek", mengikuti prinsip "jika berjalan seperti bebek dan dukun seperti bebek ..." yang memungkinkan substitusi informal objek dengan subset metode umum tanpa pewarisan eksplisit atau hubungan mixin.

Mike Woodhouse
sumber
Terima kasih. Ada satu hal yang saya benci tentang metode kirim : metode ini memungkinkan Anda memanggil metode pribadi bahkan di luar kelas! Aduh.
MiniQuark
1
@MiniQuark: itulah yang saya suka tentang metode kirim!
Andrew Grimm
6

Jika Anda mendeklarasikan penyetel (alias mutator) menggunakan attr_writeratau attr_accessor(atau def foo=), berhati-hatilah saat memanggilnya dari dalam kelas. Karena variabel secara implisit dideklarasikan, interpreter selalu harus menyelesaikan foo = barsebagai mendeklarasikan variabel baru bernama foo, daripada memanggil metode 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

Ini juga berlaku untuk objek Rails ActiveRecord, yang mendapatkan pengakses yang ditentukan berdasarkan bidang dalam database. Karena keduanya bukan variabel instan @ -style, cara yang tepat untuk menetapkan nilai tersebut satu per satu adalah dengan self.value = 123atau self['value'] = 123.

AlexChaffee
sumber
5

Memahami perbedaan antara kelas Waktu dan Tanggal. Keduanya berbeda dan telah menimbulkan masalah saat menggunakannya di rel. Kelas Time terkadang bentrok dengan pustaka kelas Time lainnya yang ada di pustaka ruby ​​/ rails standar. Secara pribadi, saya membutuhkan banyak waktu untuk memahami apa yang sebenarnya terjadi di aplikasi rel saya. Kemudian, saya pikir ketika saya melakukannya

Time.new

Itu mengacu pada beberapa perpustakaan di lokasi yang bahkan tidak saya sadari.

Maaf jika saya tidak jelas dengan apa yang ingin saya katakan dengan tepat. Jika orang lain menghadapi masalah serupa, jelaskan kembali.

Chirantan
sumber
4

Salah satu yang menarik perhatian saya di masa lalu adalah bahwa karakter baris baru ( \n) escape sequence — antara lain — tidak didukung oleh string dalam tanda kutip tunggal. Garis miring terbalik itu sendiri akan lolos. Anda harus menggunakan tanda kutip ganda agar pelolosan berfungsi seperti yang diharapkan.

John Topley
sumber
1
Dan itu berbeda dengan bahasa lain apa?
Robert Gamble
Jawa, salah satunya. Tanda kutip tunggal di Java hanya dapat digunakan untuk menyertakan satu karakter, bukan String.
John Topley
1
Ini sesuai dengan bahasa apa pun yang memungkinkan Anda menggunakan tanda kutip tunggal untuk string, dan itulah alasannya.
singpolyma
@ John: true, tetapi '\ n' di Java akan tetap menjadi karakter baris baru.
Jorn
1
Tapi di Java tanda kutip tunggal hanya membuat nilai bertipe char. Bukan string. Itulah perbedaannya.
jmucchiello
4
x = (true and false) # x is false

0 dan '' benar, seperti yang Anda tunjukkan.

Anda dapat memiliki metode dan modul / kelas dengan nama yang sama (yang masuk akal, karena metode tersebut benar-benar ditambahkan ke Objek dan dengan demikian memiliki namespace sendiri).

Tidak ada beberapa pewarisan, tetapi sering kali "modul mixin" digunakan untuk menambahkan metode umum ke beberapa kelas.

singpolyma
sumber
0 == true // argh kompiler c di otak saya meledak !!
kenny
1
0 == true memberikan false di Ruby. 0 itu benar masuk akal karena true adalah objek di Ruby. Di C 0 kebetulan memiliki representasi yang sama dengan false.
Jules
Dalam kondisi di Ruby, only falseand nilare false. Semua yang lain adalah nilai-nilai sejati.
rubyprince
4

Metode dapat didefinisikan ulang dan dapat menjadi penggaruk pikiran sampai Anda menemukan penyebabnya. ( Memang, kesalahan ini mungkin sedikit "lebih sulit" untuk dideteksi ketika tindakan pengontrol Ruby on Rails didefinisikan ulang secara tidak sengaja! )

#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

Lari:

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

Tetapi panggil dengan peringatan diaktifkan dan Anda dapat melihat alasannya:

$ ruby -w demo.rb
demo.rb:10: warning: method redefined; discarding old hello1
=> "Hello from second definition"
Zabba
sumber
Saya akan memberi +100 penggunaan peringatan jika saya bisa.
Andrew Grimm
3

Saya pikir itu selalu baik untuk menggunakan .length pada berbagai hal ... karena ukuran didukung oleh hampir semua hal dan Ruby memiliki tipe dinamis, Anda bisa mendapatkan hasil yang sangat aneh memanggil .size ketika Anda memiliki jenis yang salah ... Saya lebih suka mendapatkan a NoMethodError: metode `panjang 'yang tidak ditentukan, jadi saya biasanya tidak pernah memanggil ukuran pada objek di Ruby.

gigit aku lebih dari sekali.

Juga ingat objek memiliki id, jadi saya mencoba untuk tidak menggunakan variabel call id atau object_id hanya untuk menghindari kebingungan. Jika saya membutuhkan sebuah id pada objek Users, yang terbaik adalah menyebutnya sebagai user_id.

Hanya dua sen saya

danmayer
sumber
2

Saya baru mengenal ruby, dan pada putaran pertama saya, saya mengalami masalah tentang mengubah float / string menjadi integer. Saya mulai dengan float dan mengkodekan semuanya sebagai f.to_int . Tetapi ketika saya melanjutkan dan menggunakan metode yang sama untuk string, saya dilemparkan ke kurva ketika harus menjalankan program.

Rupanya sebuah string tidak memiliki metode to_int , tetapi float dan int punya.

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>

Tanda kurung sewenang-wenang membuat saya pada awalnya juga. Saya melihat beberapa kode dengan dan beberapa tanpa. Butuh beberapa saat bagi saya untuk menyadari bahwa gaya mana pun diterima.

monkut
sumber
2

Terkait dengan tanggapan monkut, to_foometode Ruby mengisyaratkan seberapa ketat konversi yang akan mereka lakukan.

Yang singkat seperti to_i, to_skatakan padanya untuk malas, dan konversikan ke jenis target meskipun mereka tidak dapat direpresentasikan secara akurat dalam format itu. Sebagai contoh:

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

Fungsi eksplisit yang lebih panjang seperti to_int, to_sberarti bahwa objek dapat direpresentasikan secara asli sebagai jenis data itu. Misalnya, Rationalkelas mewakili semua bilangan rasional, sehingga dapat langsung direpresentasikan sebagai bilangan bulat Fixnum (atau Bignum) dengan memanggil to_int.

Rational(20,4).to_int == 5

Jika Anda tidak dapat memanggil metode yang lebih panjang, itu berarti objek tidak dapat direpresentasikan secara asli dalam tipe itu.

Jadi pada dasarnya, saat mengonversi, jika Anda malas dengan nama metode, Ruby akan malas dengan konversi.

Luke
sumber
1
Apakah "malas" adalah kata yang tepat di sini?
Andrew Grimm
0

Yang ini membuatku marah sekali:

1/2 == 0.5 #=> false
1/2 == 0   #=> true
Andrei
sumber
Saya yakin ini akan berperilaku persis sama di Java, C, dan C ++.
Larry
Itu lucu, saya bahkan tidak memikirkannya, tetapi jika Anda membuka irb dan mencoba ini, itu masuk akal: Jadi (1/2) adalah Fixnum dan (0,5) adalah Float. Dan kita tahu bahwa Fixnim! = Float.
DemitryT
2
@DemitryT Saya pikir alasan yang lebih sederhana adalah yang 1/2mengevaluasi 0, yang tidak sama 0.5, apa pun jenisnya. Namun Rational(1, 2) == 0.5,, dan 1.0 == 1.
Max Nanasy
kesulitan bahasa universal di sini. ini adalah sesuatu yang harus diketahui oleh seseorang yang baru mengenal ruby ​​DAN pemrograman.
dtc
0
1..5.each {|x| puts x}

tidak bekerja. Anda harus memasukkan rentang ke dalam tanda kurung, seperti

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

sehingga tidak berpikir Anda menelepon 5.each. Saya pikir ini adalah masalah prioritas, seperti x = true and falsegotcha.

Andrew Grimm
sumber
Saya akan menyebutnya sebagai kurung. Kedua, jika ada kode yang tampak seperti memiliki masalah nilai kembali / prioritas, tetap harus diapit oleh tanda kurung. Jadi, bagi saya tidak ada yang istimewa dari "gotcha" ini. Anda dapat terus menulis setiap "gotcha" kombinasional, itu akan membuang-buang waktu. Terus terang sobat, bahkan jika Anda mendapatkan hasil yang diharapkan untuk ini, saya masih lebih suka menggunakan tanda kurung.
Özgür