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?
true and false
kembali benar?Jawaban:
Wikipedia Ruby gotchas
Dari artikel:
$
dan@
tidak menunjukkan tipe data variabel seperti di Perl, melainkan berfungsi sebagai operator resolusi cakupan.99.0
) atau konversi eksplisit (99.to_f
). Tidak cukup menambahkan titik (99.
), karena angka rentan terhadap sintaks metode.0
,""
dan[]
semua dievaluasi untuktrue
. Dalam C, ekspresi0 ? 1 : 0
mengevaluasi ke0
(yaitu salah). Di Ruby, bagaimanapun, itu menghasilkan1
, karena semua angka mengevaluasitrue
; hanyanil
danfalse
evaluasi kefalse
. 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, tetapinil
pada kegagalan (misalnya, ketidakcocokan). Konvensi ini juga digunakan di Smalltalk, di mana hanya objek khusustrue
danfalse
dapat digunakan dalam ekspresi boolean.char
untuk karakter). Hal ini dapat menyebabkan kejutan saat memotong string:"abc"[0]
hasil97
(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 (misalnyado { statement } while (not(expression));
dalam C / C ++ / ...), sebenarnya tidak pernah menjalankan pernyataan jika ekspresi sudah adatrue
. Ini karenastatement until expression
sebenarnya gula sintaksis sudah berakhir, padanannya dalam C / C ++ sama
while (not(expression)) statement;
sajastatement if expression
denganNamun, notasinya
di Ruby sebenarnya akan menjalankan pernyataan satu kali bahkan jika ekspresi tersebut sudah benar.
Greeting << " world!" if Greeting == "Hello"
tidak menghasilkan kesalahan atau peringatan. Ini mirip denganfinal
variabel 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,
and
danor
, jangan mengikuti aturan normal yang diutamakan:and
tidak mengikat lebih darior
. Ruby juga memiliki operator ekspresi||
dan&&
berfungsi seperti yang diharapkan.def
di dalamnyadef
tidak melakukan apa yang diharapkan programmer Python:Ini memberikan kesalahan tentang
x
tidak didefinisikan. Anda perlu menggunakan fileProc
.Fitur bahasa
()
, 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 dipanggilmethod_missing()
.sumber
Pemula akan mengalami masalah dengan metode kesetaraan :
Contoh berikut seharusnya menjelaskan 3 metode pertama:
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:
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:
The kasus Pernyataan ini didasarkan pada === metode:
setara dengan ini:
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:
sumber
Menambal monyet . Ruby memiliki kelas terbuka, sehingga perilakunya dapat diubah secara dinamis pada saat runtime ...
Objek mungkin merespons metode yang tidak ditentukan jika
method_missing
atausend
telah diganti. Ini mengeksploitasi pemanggilan metode berbasis pesan Ruby. Rails ' ActiveRecord sistem menggunakan ini untuk efek yang besar.sumber
Kode berikut mengejutkan saya. Saya pikir itu adalah gotcha yang berbahaya: mudah ditemui, dan sulit untuk di-debug.
Ini mencetak:
Tetapi jika saya menambahkan
comment =
apa pun sebelum blok ...Kemudian saya mendapatkan:
Pada dasarnya, ketika sebuah variabel hanya didefinisikan di dalam sebuah blok, maka ia dihancurkan di akhir blok, dan kemudian direset ke
nil
setiap 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:
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.sumber
a = (b if c)
untuk mendapatkan efek yang diinginkan, tanpa terner. Ini karenab if c
mengevaluasi ke nihil jikac
salah.Saat memanggil
super
tanpa argumen, metode yang ditimpa sebenarnya dipanggil dengan argumen yang sama dengan metode penggantian.Untuk benar-benar menelepon
super
tanpa argumen, Anda perlu mengatakannyasuper()
.sumber
B#hello
memilikiname = 42
sebelumsuper
, maka dikatakan "halo 42".Blok dan metode mengembalikan nilai baris terakhir secara default. Menambahkan
puts
pernyataan di akhir untuk tujuan debugging dapat menyebabkan efek samping yang tidak menyenangkansumber
Inheritence tidak berperan dalam menentukan visibilitas metode di Ruby.
sumber
Saya mengalami banyak kesulitan dalam memahami variabel kelas, atribut kelas, dan metode kelas. Kode ini mungkin membantu pemula:
sumber
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.
sumber
a = b if a.nil?
atau@a = b unless defined?(@a)
.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.sumber
Saya mengalami masalah dengan mixin yang berisi metode instance dan metode kelas. Kode ini mungkin membantu pemula:
Pada awalnya, saya pikir saya dapat memiliki modul dengan metode instance dan metode kelas hanya dengan melakukan ini:
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).
sumber
Perhatikan notasi Range.
(Setidaknya, lebih perhatikan daripada yang saya lakukan pada awalnya!)
Ada perbedaan antara
0..10
(dua titik) dan0...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:
seharusnya tidak dapat menyebabkan bug yang menghancurkan satu per satu dalam program saya.
sumber
for (i=0; i<max; i++)
danfor (i=0; i<=max; i++)
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_missing
benar-benar lebih sepertimessage_not_understood
.setara dengan
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.
sumber
Jika Anda mendeklarasikan penyetel (alias mutator) menggunakan
attr_writer
atauattr_accessor
(ataudef foo=
), berhati-hatilah saat memanggilnya dari dalam kelas. Karena variabel secara implisit dideklarasikan, interpreter selalu harus menyelesaikanfoo = bar
sebagai mendeklarasikan variabel baru bernama foo, daripada memanggil metodeself.foo=(bar)
.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 = 123
atauself['value'] = 123
.sumber
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.
sumber
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.sumber
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.
sumber
false
andnil
are false. Semua yang lain adalah nilai-nilai sejati.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! )
Lari:
Tetapi panggil dengan peringatan diaktifkan dan Anda dapat melihat alasannya:
sumber
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
sumber
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.
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.
sumber
Terkait dengan tanggapan monkut,
to_foo
metode Ruby mengisyaratkan seberapa ketat konversi yang akan mereka lakukan.Yang singkat seperti
to_i
,to_s
katakan padanya untuk malas, dan konversikan ke jenis target meskipun mereka tidak dapat direpresentasikan secara akurat dalam format itu. Sebagai contoh:Fungsi eksplisit yang lebih panjang seperti
to_int
,to_s
berarti bahwa objek dapat direpresentasikan secara asli sebagai jenis data itu. Misalnya,Rational
kelas mewakili semua bilangan rasional, sehingga dapat langsung direpresentasikan sebagai bilangan bulat Fixnum (atau Bignum) dengan memanggilto_int
.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.
sumber
Dari In Ruby mengapa tidak mau
foo = true unless defined?(foo)
membuat tugas?Karena
foo
diartikan sebagainil
saatdefined?(foo)
dipanggil.sumber
Iterasi pada hash ruby tidak dijamin akan terjadi dalam urutan tertentu. (Ini bukan bug, ini fitur)
Hash#sort
berguna jika Anda membutuhkan pesanan tertentu.Pertanyaan terkait: Mengapa susunan kunci dan pasangan nilai 1000 hashes Ruby selalu dalam urutan tertentu?
sumber
Yang ini membuatku marah sekali:
sumber
1/2
mengevaluasi0
, yang tidak sama0.5
, apa pun jenisnya. NamunRational(1, 2) == 0.5
,, dan1.0 == 1
.tidak bekerja. Anda harus memasukkan rentang ke dalam tanda kurung, seperti
sehingga tidak berpikir Anda menelepon
5.each
. Saya pikir ini adalah masalah prioritas, sepertix = true and false
gotcha.sumber