Content | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11

Official Ruby FAQ

If you wish to report errors or suggest improvements for this FAQ, please go to our GitHub repository and open an issue or pull request.

Cú pháp

Sự khác biệt giữa giá trị trực tiếp và tham chiếu là gì?

This section or parts of it might be out-dated or in need of confirmation.

Fixnum, true, nilfalse được triển khai dưới dạng giá trị trực tiếp. Với giá trị trực tiếp, biến chứa chính đối tượng, thay vì tham chiếu đến chúng.

Không thể định nghĩa phương thức singleton cho các đối tượng như vậy. Hai Fixnum có cùng giá trị luôn đại diện cho cùng một thể hiện đối tượng, nên (ví dụ) các biến thể hiện cho Fixnum có giá trị 1 được chia sẻ giữa tất cả các 1 trong hệ thống. Điều này khiến việc định nghĩa phương thức singleton cho chỉ một trong số chúng là không thể.

Sự khác biệt giữa nilfalse là gì?

Trước hết là điểm tương đồng: nilfalse là hai đối tượng duy nhất được đánh giá là false trong ngữ cảnh boolean. (Nói cách khác: chúng là hai giá trị “falsy” duy nhất, tất cả các đối tượng khác đều là “truthy”.)

Tuy nhiên, nilfalse là thể hiện của các lớp khác nhau (NilClassFalseClass), và có hành vi khác nhau ở những chỗ khác.

Chúng tôi khuyến nghị các phương thức vị ngữ (những phương thức có tên kết thúc bằng dấu hỏi) nên trả về true hoặc false. Các phương thức khác cần chỉ ra sự thất bại nên trả về nil.

Tại sao chuỗi rỗng không phải là false?

H: Một chuỗi rỗng ("") trả về true trong biểu thức điều kiện! Trong Perl, nó là false.

Đ: Nhưng Ruby không phải là Perl ;-). Rất đơn giản: trong Ruby, chỉ có nilfalse là false trong ngữ cảnh điều kiện.

Bạn có thể sử dụng empty?, so sánh chuỗi với "", hoặc so sánh size hoặc length của chuỗi với 0 để kiểm tra xem một chuỗi có rỗng hay không.

:name có ý nghĩa gì?

Một dấu hai chấm theo sau bởi một tên tạo ra một đối tượng Symbol tương ứng một-một với định danh đó. Trong suốt thời gian thực thi chương trình, cùng một đối tượng Symbol sẽ được tạo cho một tên hoặc chuỗi nhất định. Symbol cũng có thể được tạo bằng "name".intern hoặc "name".to_sym.

Các đối tượng Symbol có thể đại diện cho các định danh của phương thức, biến, v.v. Một số phương thức, như define_method, method_missing hoặc trace_var, yêu cầu một symbol. Các phương thức khác, ví dụ attr_accessor, send hoặc autoload, cũng chấp nhận chuỗi.

Do chỉ được tạo một lần, Symbol thường được sử dụng làm khóa hash. Khóa hash dạng chuỗi sẽ tạo một đối tượng mới cho mỗi lần sử dụng, gây ra một số chi phí bộ nhớ. Thậm chí còn có cú pháp đặc biệt cho khóa hash dạng symbol:

person_1 = { :name => "John", :age => 42 }
person_2 = { name: "Jane", age: 24 }        # alternate syntax

Symbol cũng có thể được sử dụng làm giá trị liệt kê hoặc để gán giá trị duy nhất cho các hằng số:

status = :open  # :closed, ...

NORTH = :NORTH
SOUTH = :SOUTH

Làm thế nào để truy cập giá trị của symbol?

Để lấy giá trị của biến tương ứng với một symbol, bạn có thể sử dụng symbol.to_s hoặc "#{symbol}" để lấy tên của biến, rồi eval nó trong phạm vi của symbol để lấy nội dung của biến:

a = "This is the content of `a'"
b = eval("#{:a}")
a.object_id == b.object_id  # => true

Bạn cũng có thể sử dụng

b = binding.local_variable_get(:a)

Nếu symbol của bạn tương ứng với tên một phương thức, bạn có thể sử dụng send:

class Demo
  def hello
    "Hello, world"
  end
end

demo = Demo.new
demo.send(:hello)

Hoặc bạn có thể sử dụng Object#method để trả về đối tượng Method tương ứng, rồi gọi nó:

m = demo.method(:hello)  # => #<Method: Demo#hello>
m.call                   # => "Hello, world"

loop có phải là cấu trúc điều khiển không?

Mặc dù loop trông giống như một cấu trúc điều khiển, nhưng thực chất nó là một phương thức được định nghĩa trong Kernel. Khối theo sau tạo ra một phạm vi mới cho các biến cục bộ.

Ruby không có vòng lặp kiểm tra điều kiện sau

H: Ruby không có cấu trúc do { ... } while, vậy làm thế nào để triển khai các vòng lặp kiểm tra điều kiện ở cuối?

Clemens Hintze nói: Bạn có thể sử dụng kết hợp begin ... end của Ruby và bổ ngữ while hoặc until để đạt được hiệu quả tương tự:

i = 0
begin
  puts "i = #{i}"
  i += 1
end until i > 4

Kết quả:

i = 0
i = 1
i = 2
i = 3
i = 4

Tại sao tôi không thể truyền hash literal cho phương thức: p {}?

{} được phân tích cú pháp như một khối, không phải hàm tạo Hash. Bạn có thể buộc {} được xử lý như một biểu thức bằng cách chỉ rõ rằng nó là một tham số: p({}).

Tôi không thể làm cho def pos=(val) hoạt động!

Tôi có đoạn mã sau, nhưng không thể sử dụng phương thức pos = 1.

def pos=(val)
  @pos = val
  puts @pos
end

Các phương thức có = ở cuối phải được gọi với bộ nhận tường minh (nếu không có bộ nhận, bạn chỉ đang gán cho một biến cục bộ). Gọi nó bằng self.pos = 1.

Sự khác biệt giữa '\1''\\1' là gì?

Chúng có cùng ý nghĩa. Trong chuỗi nháy đơn, chỉ \'\\ được chuyển đổi và các tổ hợp khác giữ nguyên.

Tuy nhiên, trong chuỗi nháy kép, "\1" là byte \001 (một mẫu bit bát phân), trong khi "\\1" là chuỗi hai ký tự chứa một dấu gạch chéo ngược và ký tự "1".

Sự khác biệt giữa ..... là gì?

.. bao gồm giá trị bên phải trong phạm vi, ... thì không:

(5..8).to_a   # => [5, 6, 7, 8]
(5...8).to_a  # => [5, 6, 7]

Sự khác biệt giữa or|| là gì?

H: p(nil || "Hello") in ra "Hello", trong khi p(nil or "Hello") gây ra lỗi phân tích cú pháp. Tại sao?

Đ: or có mức ưu tiên rất thấp, p( (nil or "Hello") ) sẽ hoạt động.

Mức ưu tiên của or ví dụ cũng thấp hơn so với =, trong khi || có mức ưu tiên cao hơn:

foo = nil || "Hello"  # parsed as: foo = (nil || "Hello")
foo  # => "Hello"

# but perhaps surprisingly:

foo = nil or "Hello"  # parsed as: (foo = nil) or "Hello"
foo  # => nil

or (và tương tự and) tốt nhất nên được sử dụng không phải để kết hợp các biểu thức boolean, mà cho luồng điều khiển, như trong

do_something  or raise "some error!"

trong đó do_something trả về false hoặc nil khi có lỗi xảy ra.

Ruby có con trỏ hàm không?

Đối tượng Proc được tạo bởi Proc.new, proc hoặc lambda có thể được tham chiếu từ một biến, nên biến đó có thể được coi là một con trỏ hàm. Bạn cũng có thể lấy tham chiếu đến các phương thức trong một thể hiện đối tượng cụ thể bằng object.method.

Sự khác biệt giữa loadrequire là gì?

load sẽ nạp và thực thi một chương trình Ruby (*.rb).

require cũng nạp các chương trình Ruby, nhưng còn nạp các module mở rộng Ruby dạng nhị phân (thư viện chia sẻ hoặc DLL). Ngoài ra, require đảm bảo rằng một tính năng không bao giờ được nạp nhiều hơn một lần.

Ruby có xử lý ngoại lệ không?

Ruby hỗ trợ cơ chế xử lý ngoại lệ linh hoạt:

begin
  statements which may raise exceptions
rescue [exception class names]
  statements when an exception occurred
rescue [exception class names]
  statements when an exception occurred
ensure
  statements that will always run
end

Nếu một ngoại lệ xảy ra trong mệnh đề begin, mệnh đề rescue có tên ngoại lệ phù hợp sẽ được thực thi. Mệnh đề ensure được thực thi bất kể có ngoại lệ xảy ra hay không. Các mệnh đề rescueensure có thể được bỏ qua.

Nếu không có lớp ngoại lệ nào được chỉ định cho mệnh đề rescue, ngoại lệ StandardError được ngụ ý, và các ngoại lệ có quan hệ is_a? với StandardError sẽ được bắt.

Biểu thức này trả về giá trị của mệnh đề begin.

Ngoại lệ mới nhất được truy cập bằng biến toàn cục $! (và do đó kiểu của nó có thể được xác định bằng $!.type).