Pengecualian Ruby


Pengecualian dan pelaksanaan sentiasa dikaitkan bersama. Jika anda membuka fail yang tidak wujud dan tidak mengendalikan situasi dengan sewajarnya, program anda dianggap berkualiti rendah.

Jika pengecualian berlaku, program akan berhenti. Pengecualian digunakan untuk mengendalikan pelbagai jenis ralat yang mungkin berlaku semasa pelaksanaan program, jadi tindakan sewajarnya diambil tanpa menghentikan program sepenuhnya.

Ruby menyediakan mekanisme yang sempurna untuk mengendalikan pengecualian. Kita boleh menyertakan kod yang mungkin membuang pengecualian dalam blok mula/akhir dan menggunakan klausa menyelamat untuk memberitahu Ruby jenis pengecualian yang perlu dikendalikan.

Sintaks

begin #开始
 
 raise.. #抛出异常
 
rescue [ExceptionType = StandardException] #捕获指定类型的异常 缺省值是StandardException
 $! #表示异常信息
 $@ #表示异常出现的代码位置
else #其余异常
 ..
ensure #不管有没有异常,进入该代码块
 
end #结束

Segala-galanya daripada bermula hingga menyelamatkan dilindungi. Jika pengecualian berlaku semasa pelaksanaan blok kod, kawalan diserahkan kepada blok antara menyelamat dan tamat.

Untuk setiap klausa menyelamat dalam blok mula, Ruby membandingkan pengecualian yang dilemparkan dengan setiap hujah secara bergilir-gilir. Jika pengecualian yang dinamakan dalam klausa penyelamat adalah daripada jenis yang sama seperti pengecualian yang dilemparkan pada masa ini, atau merupakan kelas induk pengecualian itu, perlawanan itu berjaya.

Jika pengecualian tidak sepadan dengan semua jenis ralat yang ditentukan, kita boleh menggunakan klausa else selepas semua klausa menyelamat.

Contoh

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
      file = STDIN
end
print file, "==", STDIN, "\n"

Hasil keluaran contoh di atas ialah. Anda boleh melihat bahawa STDIN ​​​​menggantikan fail kerana gagal membuka .

#<IO:0xb7d16f84>==#<IO:0xb7d16f84>

Gunakan cuba semula pernyataan

Anda boleh menggunakan blok menyelamat untuk menangkap pengecualian dan kemudian gunakan pernyataan cuba semula untuk memulakan pelaksanaan dari awal mula blok.

Syntax

begin
    # 这段代码抛出的异常将被下面的 rescue 子句捕获
rescue
    # 这个块将捕获所有类型的异常
    retry  # 这将把控制移到 begin 的开头
end

Instance

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
   fname = "existant_file"
   retry
end

Berikut ialah aliran pemprosesan:

  • Pengecualian berlaku semasa membuka.

  • Lompat untuk menyelamatkan. fname ditugaskan semula.

  • Lompat ke permulaan permulaan melalui cuba semula.

  • Kali ini fail berjaya dibuka.

  • Teruskan dengan proses asas.

Nota: Jika fail yang dinamakan semula tidak wujud, kod daya ini akan mencuba tanpa had. Oleh itu, gunakan cuba semula dengan berhati-hati apabila mengendalikan pengecualian.

Menggunakan pernyataan raise

Anda boleh menggunakan pernyataan raise untuk membuang pengecualian. Kaedah berikut membuang pengecualian apabila dipanggil. Mesej kedua akan dikeluarkan.

Syntax

raise 

或

raise "Error Message" 

或

raise ExceptionType, "Error Message"

或

raise ExceptionType, "Error Message" condition

Borang pertama hanya membuang semula pengecualian semasa (atau RuntimeError jika tiada pengecualian semasa). Ini digunakan dalam pengendali pengecualian yang perlu mentafsir pengecualian sebelum menyerahkannya.

Borang kedua mencipta pengecualian RuntimeError baharu, menetapkan mesejnya kepada rentetan yang diberikan. Pengecualian kemudiannya dilemparkan ke atas timbunan panggilan.

Borang ketiga mencipta pengecualian menggunakan parameter pertama, dan kemudian menetapkan mesej berkaitan sebagai parameter kedua.

Borang keempat adalah serupa dengan borang ketiga, anda boleh menambah sebarang pernyataan bersyarat tambahan (seperti melainkan) untuk membuang pengecualian.

Instance

#!/usr/bin/ruby

begin  
    puts 'I am before the raise.'  
    raise 'An error has occurred.'  
    puts 'I am after the raise.'  
rescue  
    puts 'I am rescued.'  
end  
puts 'I am after the begin block.'

Contoh di atas menjalankan hasil output ialah:

I am before the raise.  
I am rescued.  
I am after the begin block.

Contoh lain yang menunjukkan penggunaan raise:

#!/usr/bin/ruby

begin  
  raise 'A test exception.'  
rescue Exception => e  
  puts e.message  
  puts e.backtrace.inspect  
end

di atas Hasil keluaran contoh berjalan ialah:

A test exception.
["main.rb:4"]

Gunakan pernyataan pastikan

Kadangkala, tidak kira sama ada pengecualian dilemparkan, anda perlu memastikan bahawa beberapa pemprosesan selesai pada penghujung blok kod. Sebagai contoh, anda mungkin mempunyai fail terbuka apabila anda masuk, dan apabila anda keluar dari blok, anda perlu memastikan anda menutup fail tersebut.

Klausa

pastikan melakukan perkara itu. pastikan diletakkan selepas klausa penyelamat terakhir dan mengandungi blok kod yang sentiasa dilaksanakan apabila blok ditamatkan. Tidak kira sama ada blok itu keluar dengan anggun, sama ada ia melontar dan mengendalikan pengecualian, atau sama ada ia ditamatkan dengan pengecualian yang tidak ditangkap, blok pastikan akan sentiasa berjalan.

Sintaks

begin 
   #.. 过程
   #.. 抛出异常
rescue 
   #.. 处理错误 
ensure 
   #.. 最后确保执行
   #.. 这总是会执行
end

Contoh

begin
  raise 'A test exception.'
rescue Exception => e
  puts e.message
  puts e.backtrace.inspect
ensure
  puts "Ensuring execution"
end

Keluaran contoh di atas ialah:

A test exception.
["main.rb:4"]
Ensuring execution

Gunakan pernyataan else

Jika klausa lain disediakan, ia biasanya diletakkan selepas klausa menyelamat dan sebelum mana-mana pastikan. Badan klausa

else hanya dilaksanakan jika badan kod tidak membuang pengecualian.

Sintaks

begin 
   #.. 过程 
   #.. 抛出异常
rescue 
   #.. 处理错误
else
   #.. 如果没有异常则执行
ensure 
   #.. 最后确保执行
   #.. 这总是会执行
end

Contoh

begin
 # 抛出 'A test exception.'
 puts "I'm not raising exception"
rescue Exception => e
  puts e.message
  puts e.backtrace.inspect
else
   puts "Congratulations-- no errors!"
ensure
  puts "Ensuring execution"
end

Keluaran contoh di atas ialah:

I'm not raising exception
Congratulations-- no errors!
Ensuring execution

Gunakan pembolehubah $! Mekanisme pengecualian

Catch and Throw

raise and rescue boleh menghentikan pelaksanaan apabila ralat berlaku Kadangkala perlu untuk melompat keluar dari beberapa struktur bersarang dalam semasa pemprosesan biasa. Di sinilah tangkapan dan lempar berguna.

catch mentakrifkan blok yang menggunakan nama yang diberikan (yang boleh menjadi Simbol atau Rentetan) sebagai label. Blok akan dilaksanakan seperti biasa sehingga lontaran ditemui.

Sintaks

throw :lablename
#.. 这不会被执行
catch :lablename do
#.. 在遇到一个 throw 后匹配将被执行的 catch
end

或

throw :lablename condition
#.. 这不会被执行
catch :lablename do
#.. 在遇到一个 throw 后匹配将被执行的 catch
end

Contoh

Dalam contoh berikut, jika pengguna menaip '!' sebagai tindak balas kepada sebarang gesaan, lontaran digunakan untuk menamatkan interaksi dengan pengguna .

def promptAndGet(prompt)
   print prompt
   res = readline.chomp
   throw :quitRequested if res == "!"
   return res
end

catch :quitRequested do
   name = promptAndGet("Name: ")
   age = promptAndGet("Age: ")
   sex = promptAndGet("Sex: ")
   # ..
   # 处理信息
end
promptAndGet("Name:")

Program di atas memerlukan interaksi manusia, anda boleh mencubanya pada komputer anda. Hasil keluaran contoh di atas ialah:

Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby

Pengecualian Kelas

Kelas dan modul standard Ruby membuang pengecualian. Semua kelas pengecualian membentuk hierarki, termasuk kelas Pengecualian di bahagian atas. Tahap seterusnya ke bawah ialah tujuh jenis yang berbeza:

  • Interrupt

  • NoMemoryError

  • SignalException

  • ScriptError

  • StandardError

  • SystemExit

Fatal adalah satu lagi pengecualian dalam lapisan ini, tetapi penterjemah Ruby hanya menggunakannya secara dalaman.

Kedua-dua ScriptError dan StandardError mempunyai beberapa subkelas, tetapi kami tidak perlu mengetahui butiran tersebut di sini. Perkara yang paling penting ialah mencipta kelas pengecualian kita sendiri, mereka mestilah subkelas kelas Pengecualian atau keturunannya.

Mari kita lihat contoh:

class FileSaveError < StandardError
   attr_reader :reason
   def initialize(reason)
      @reason = reason
   end
end

Sekarang, lihat contoh berikut di mana pengecualian di atas akan digunakan:

File.open(path, "w") do |file|
begin
    # 写出数据 ...
rescue
    # 发生错误
    raise FileSaveError.new($!)
end
end

Di sini, baris yang paling penting ialah naikkan FileSaveError.new($!). Kami memanggil kenaikan untuk menunjukkan bahawa pengecualian telah berlaku, menyerahkannya kepada contoh baharu FileSaveError yang gagal menulis data disebabkan pengecualian khusus.