Jenis kelas dan pernyataan kasus Ruby

135

Apa perbedaan antara

case item.class
when MyClass
  # do something here
when Array
  # do something different here
when String
  # do a third thing
end

dan

case item.class
when MyClass.class
  # do something here
when Array.class
  # do something different here
when String.class
  # do a third thing
end

Untuk beberapa alasan, yang pertama kadang-kadang bekerja dan yang kedua tidak, dan kali lain, yang kedua bekerja dan yang pertama tidak. Mengapa? Mana yang merupakan cara yang "tepat" untuk melakukannya?

Daisy Sophia Hollman
sumber
1
String adalah kelas. Kelas suatu kelas adalah Kelas.
Volte
Catatan yang MyClass === objmenggunakan metode Module # === untuk memeriksa apakah objmerupakan instance dari MyClass.
sergio

Jawaban:

234

Anda harus menggunakan:

case item
when MyClass
...

Saya memiliki masalah yang sama: Bagaimana cara menangkap kelas Errno :: ECONNRESET di "case when"?

Nakilon
sumber
1
Terima kasih! Maaf untuk menipu (atau semacam penipuan), tetapi beberapa pencarian tidak muncul pertanyaan sebelumnya. Tampaknya penggunaan === oleh pernyataan kasus cukup masalah umum, sekarang saya melihat ini masalahnya. Ini mungkin harus lebih sering ditunjukkan dalam tutorial dan semacamnya (tapi saya yakin banyak penulis tutorial juga tidak mengetahui hal ini).
Daisy Sophia Hollman
4
Peringatan yang belum disebutkan jika menggunakan ActiveRecord. Metode ActiveRecord === pada perbandingan kelas menggunakan .is_a ?, yang berarti bahwa subkelas kelas akan mengevaluasi true dalam pernyataan kasus. github.com/rails/rails/blob/…
Jeremy Baker
61

Ya, Nakilon benar, Anda harus tahu bagaimana operator threequal === bekerja pada objek yang diberikan dalam whenklausa. Di Ruby

case item
when MyClass
...
when Array
...
when String
...

benar-benar

if MyClass === item
...
elsif Array === item
...
elsif String === item
...

Memahami bahwa case memanggil metode threequal ( MyClass.===(item)misalnya), dan metode itu dapat didefinisikan untuk melakukan apa pun yang Anda inginkan, dan kemudian Anda dapat menggunakan pernyataan case dengan precisionw

Fred
sumber
Jika sudah arr = []maka saya perhatikan bahwa if Array === arrakan mengevaluasi ke true tetapi if arr === Arrayakan mengevaluasi ke false. Bisakah seseorang tolong bantu menjelaskan?
Daniel
4
=== hanyalah sebuah metode yang dapat didefinisikan untuk melakukan apa pun yang diinginkan oleh perancang kelas. Ingat juga, bahwa a === b benar-benar berarti a. === b, jadi jika Anda beralih a dan b di sekitar, Anda bisa mendapatkan perilaku yang berbeda. Tidak ada jaminan bahwa === bersifat komutatif. Faktanya, Array === Array itu salah, tetapi Object === Object itu benar, jadi Array mendefinisikan ulang semantik dari ===.
Fred
13

Kamu bisa memakai:

case item.class.to_s
    when 'MyClass'

... ketika putaran berikut tidak memungkinkan:

case item
    when MyClass

Alasan untuk ini adalah yang casemenggunakan ===, dan hubungan yang ===dijelaskan oleh operator tidak bersifat komutatif . Sebagai contoh, 5adalah Integer, tetapi Integersebuah 5? Ini adalah bagaimana Anda harus memikirkan case/ when.

user664833
sumber
5

Di Ruby, nama kelas adalah konstanta yang merujuk ke objek tipe Classyang menggambarkan kelas tertentu. Itu berarti mengatakan MyClassdi Ruby sama dengan mengatakan MyClass.classdi Java.

obj.classadalah objek bertipe Classmenggambarkan kelas obj. Jika obj.classini MyClass, maka objdibuat menggunakan MyClass.new(berbicara kasar). MyClassadalah objek bertipe Classyang menjelaskan objek apa pun yang dibuat menggunakan MyClass.new.

MyClass.classadalah kelas dari MyClassobjek (itu adalah kelas dari objek tipe Classyang menggambarkan objek yang dibuat menggunakan MyClass.new). Dengan kata lain MyClass.class == Class,.

Ken Bloom
sumber
1

Itu tergantung pada sifat itemvariabel Anda . Jika itu adalah instance dari objek, misalnya

t = 5

kemudian

t.class == Fixnum

tetapi jika itu adalah kelas itu sendiri misalnya

t = Array

maka itu akan menjadi Classobjek, jadi

t.class == Class

EDIT : silakan merujuk ke Cara menangkap kelas Errno :: ECONNRESET di "case when"? seperti yang dinyatakan oleh Nakilon karena jawaban saya bisa salah.

Mendongkrak
sumber
Di Ruby, semuanya adalah "turunan dari suatu objek".
Eric Duminil