Ruby sẽ cố tình ẩn một số lỗi và ngoại lệ khỏi bạn.
Đôi khi điều này có thể hữu ích.
Giống như khi sử dụng vòng lặp Kernel#loop
phương thức với một khối, vòng lặp loop
sẽ dừng khi StopIteration
ngoại lệ được nêu ra.
Nhưng những lúc khác, điều này có thể khiến phiên gỡ lỗi của bạn khó hơn rất nhiều.
Hãy xem một số ví dụ!
Ngoại lệ ẩn:Mô-đun có thể so sánh + <=> Phương pháp
Ví dụ đầu tiên liên quan đến Comparable
mô-đun &<=>
phương pháp.
Đây là ví dụ :
class MyObject attr_accessor :value include Comparable def initialize(value) @value = value end def <=>(other) raise ArgumentError, "can't compare #{other.class} with #{self.class}" unless other.is_a?(MyObject) value <=> other.valuee end end mo1 = MyObject.new(10) mo2 = MyObject.new(10) p mo1 == mo2
Hãy nói về ví dụ này.
Đầu tiên :
Chúng tôi có một lớp tên là MyObject
, với một giá trị attr_accessor
loop
và bao gồm Comparable
mô-đun, bổ sung các phương pháp so sánh (như ==
, <
, >
) đến lớp học của chúng tôi.
Các phương pháp so sánh này dựa trên <=>
phương pháp.
Giống như các phương thức Enumerable dựa trên each
phương pháp.
Sau đó :
Chúng tôi đang tạo hai đối tượng (MyObject.new
) với cùng một giá trị (10
).
Lưu ý rằng ngay cả khi chúng có cùng giá trị chúng là các đối tượng khác nhau , điều này rất quan trọng.
Bây giờ nếu chúng ta so sánh hai đối tượng này mo1
&mo2
chúng tôi nhận được false
…
Tại sao?
Bởi vì chúng tôi có lỗi trong <=>
của chúng tôi nhưng Ruby đang ẩn lỗi đó!
Nhìn kỹ…
Bạn có thể phát hiện ra lỗi không?
Nếu bạn tìm thấy nó là công việc tốt! Nếu không thì không sao 🙂
Đây rồi :
value <=> other.valuee
Xem valuee
này ?
Hóa ra chúng tôi mắc lỗi đánh máy!
Thông thường, chúng tôi sẽ nhận được NoMethodError
ngoại lệ và chúng tôi sẽ biết vấn đề là gì khá nhanh chóng. Nhưng không phải trong ví dụ này.
Tin tốt là kể từ Ruby 2.3, điều này đã thay đổi. Bạn có thể thấy lỗi ngay bây giờ vì nó không còn bị ẩn nữa.
Một lý do khác để nâng cấp nếu bạn vẫn đang chạy các phiên bản Ruby cũ hơn.
Ngoại lệ ẩn:Đối tượng số + Phương pháp cưỡng chế
Một ví dụ khác về ngoại lệ ẩn là với Numeric
đối tượng (Float
, Integer
) cộng với coerce
phương pháp.
Đây là một ví dụ :
class MyObject attr_accessor :value def initialize(value) @value = value end def +(other) other = MyObject.new(other) if other.kind_of?(Numeric) value + other.value end def coerce(other) mo = MyObject.new mo.valuee = other [mo, self] end end mo1 = MyObject.new 10 mo2 = MyObject.new 10 p mo1 + mo2 # 20 p mo1 + 20 # 30
Đây là một MyObject
khác lớp, nhưng với các phương thức mới, +
&coerce
.
coerce
phương pháp này cho phép bạn làm việc với hai loại không tương thích và biến chúng thành cùng một loại để chúng có thể hoạt động cùng nhau.
Trong trường hợp này, lớp của chúng ta đại diện cho một số giá trị số, có thể là số giây, giá hoặc bất cứ thứ gì tương tự…
Và chúng tôi muốn có thể thực hiện những loại hoạt động này :
mo1 + 20 20 + mo1
Cái đầu tiên (mo1 + 20
) dễ dàng vì chúng tôi kiểm soát +
trong lớp của chúng tôi.
Nhưng còn Integer
thì sao lớp học?
Chúng tôi có thể thay đổi +
của Integer để thực hiện điều này, nhưng đó có lẽ không phải là một ý kiến hay 🙂
Giải pháp?
Triển khai coerce
trong lớp của riêng bạn.
Một điều là +
phương thức trên Integer
sẽ làm là kiểm tra xem đối tượng của bạn có triển khai phương thức này hay không và nếu có nó sẽ gọi nó.
Bây giờ, hãy nhớ ví dụ mã ở đầu phần này?
Nếu chúng tôi cố gắng làm điều này :
20 + mo1
Chúng tôi muốn xem 30
, vì giá trị cho mo1
là 10
. Nhưng những gì chúng ta thấy là:
MyObject can't be coerced into Fixnum
Vấn đề tương tự như trước đây!
Một lỗi đang được chúng tôi ẩn bên trong coerce
phương pháp.
Cái này:mo.valuee = other
Một lần nữa, chúng tôi có một lỗi chính tả, nhưng đó không phải là lỗi đang nói!
MyObject can't be coerced into Fixnum
Tôi có tin tốt cho bạn, hành vi này đang thay đổi trong Ruby 2.5, do đó, đó sẽ là một lỗi ẩn khác sẽ biến mất, do đó bạn không phải lo lắng về nó.
Tóm tắt
Như bạn có thể thấy, đây là những ví dụ điển hình về lý do tại sao bạn muốn tránh ẩn các ngoại lệ. Bạn có thể tìm hiểu thêm về các trường hợp ngoại lệ trong cuốn sách của tôi, Ruby Deep Dive.
Tôi sẽ đánh giá cao nếu bạn chia sẻ bài đăng này với bạn bè của bạn để nhiều người có thể xem nó.
Cảm ơn vì đã đọc!