Tự viết phương thức trong Ruby
Hãy cùng tham khảo cách tự viết phương thức trong Ruby bằng ví dụ đơn giản p008mymethods.rb. Để ý rằng ta dùng def và end để khai báo một phương thức. Các tham số là danh sách các biến cục bộ nằm giữa dấu ngoặc đơn.
Đối với các hàm phương thức (phương thức có trả lại giá trị sau khi được gọi), ta không cần khai báo kiểu cho giá trị được trả lại. Phương thức sẽ trả lại giá trị ở dòng cuối cùng trong khai báo phương thức nếu không gặp từ khóa “return”. Bạn nên ngăn cách các khối mã khai báo phương thức bằng một dòng trắng. Theo quy ước trong Ruby, các tham số nên nằm giữa hai dấu ngoặc đơn. Tuy nhiên do puts, p (sẽ bàn sau) và gets được sử dụng khá nhiều nên quy tắc dấu ngoặc đơn không được áp dụng trong các trường hợp này. Trong Rails, bạn sẽ bắt gặp các lệnh gọi phương thức không có dấu ngoặc đơn.
#A simple method
def hello
puts 'Hello'
end
#use the method
hello
#Method with an argument - 1
def hello1(name)
puts 'Hello ' + name
return 'success'
end
puts(hello1('satish'))
#Method with an argument - 2
def hello2 name2
puts 'Hello ' + name2
'success'
end
puts hello2 'talim' # A method returns the value of last line
Kết quả đưa ra màn hình là:
Hello Hello satish success Hello talim success p008mymethods.rb:20: warning: parenthesize argument(s) for future version
Ruby cho phép bạn khai báo giá trị mặc định cho tham số của phương thức – giá trị mà được tự động sử dụng cho tham số không được gán trong câu lệnh gọi phương thức. Hãy xem ví dụ p009mymethods1.rb
def mtd(arg1 = "Dibya", arg2 = "Shashank", arg3 = "Shashank")
"#{arg1}, #{arg2}, #{arg3}."
end
puts mtd
puts mtd("ruby")
Kết quả là:
>ruby p009mymethods1.rb Dibya, Shashank, Shashank. ruby, Shashank, Shashank. >Exit code: 0
Trong ví dụ trên ta sử dụng #{..} để lồng giá trị của biến vào trong chuỗi. Khi chạy chương trình bạn sẽ không thấy #{..} xuất hiện trong chuỗi xuất, thay vào đó là giá trị của biến nằm bên trong nó.
Chú ý: Lồng giá trị là phương pháp chèn kết quả của một câu lệnh vào bên trong một chuỗi. Cách lồng giá trị vào một chuỗi là đặt câu lệnh vào giữa 2 kí hiệu #{ và }. Ví dụ sau minh họa cho cách này:
puts “100 * 5 = #{100 * 5}”
Kết quả đưa ra màn hình sẽ là:
100 * 5 = 500
Phần #{100 * 5} sẽ diễn giải kết quả của phép tính 100 * 5 thành một chuỗi tại vị trí đó, kết quả đưa ra màn hình sẽ là giá trị kết quả của phép tính.
Ví dụ p010aliasmtd.rb sau đây sẽ minh họa cho việc tạo bản sao của một phương thức (aliasing a method).
alias new_name old_name sẽ tạo một tên mới tham chiếu đến phương thức có tên old_name. Khi một phương thức được alias, tên mới sẽ dùng cho bản gốc của phương thức có tên cũ. Nếu phương thức cũ được khai báo lại về sau, thì tên của bản sao vẫn trỏ về phương thức gốc.
def oldmtd "old method" end alias newmtd oldmtd def oldmtd "old improved method" end puts oldmtd puts newmtd
Kết quả như sau:
>ruby p010aliasmtd.rb old improved method old method >Exit code: 0
Ruby có cho phép ta viết phương thức chấp nhận số tham số không cố định không?
Câu trả lời là có. Ta hãy cùng xem ví dụ p011vararg.rb:
def foo(*my_string)
my_string.each do |words|
puts words
end
end
foo('hello','world')
foo()
Dấu sao (*) dùng để đánh dấu my_string là mảng chứa các tham số được truyền vào. Khối mã do … end sẽ được bàn kĩ sau. Như bạn thấy, bằng cách sử dụng dấu *, ta thậm chí còn có thể không truyền tham số cho phương thức cũng được. Đoạn mã trên sẽ cho ra 2 dòng hello và world sau lệnh gọi phương thức đầu tiên. Lệnh gọi thứ hai sẽ không xuất ra màn hình dòng nào cả.
>ruby p011vararg.rb hello world >Exit code: 0
Nếu bạn muốn một phương thức chấp nhận vài tham số không bắt buộc (*x), chúng phải được xếp sau các tham số khác:
def opt_args(a,b,*x) # right def opt_args(a,*x,b) # wrong
Số tham số tối đa mà ta có thể truyền vào phương thức trong Ruby là bao nhiêu?
Không có giới hạn về số tham số. Bạn có thể tham khảo thêm tại : http://www.recentrambles.com/pragmatic/view/68
Thứ tự xếp tham số vào ngăn xếp (stack) của Ruby là thế nào? Từ trái sang phải giống C hay từ phải sang trái, giống Pascal?
Từ trái sang phải như ví dụ dưới đây (p012mtdstack.rb):
def mtd(a=99, b=a+1) [a,b] end puts mtd
Tham số được truyền bởi giá trị hay tham chiếu?
Hãy cùng quan sát ví dụ dưới đây:
def downer(string) string.downcase! end a = "HELLO" # -> "HELLO" downer(a) # -> "hello" puts a
Chú thích của người dịch: Đây là một trong những điều khá thú vị của Ruby (đối với tớ). Trong ví dụ trên, giả sử bạn thay dòng string.downcase! bằng string = ‘hello’ thì chuỗi xuất ra màn hình vẫn là ‘HELLO’. Tớ đã nói đến vấn đề này trong bài viết “Ruby – có thật sự mọi thứ đều là đối tượng”. Các bạn đọc để tham khảo nhé.
Phương thức ra lệnh
Những phương thức có chức năng thay đổi đối tượng chủ ngay sau khi kết thúc lệnh gọi và có dấu ! ở cuối tên phương thức, được gọi là phương thức ra lệnh (bang method). Sở dĩ gọi là “bang method” là để nhắc nhở lập trình viên sử dụng các phương thức này một cách cẩn thận, vì chúng có chức năng khá “nguy hiểm” so với các phương thức cùng tên nhưng không có dấu “!” ở cuối.
Thường thì bạn có thể tìm thấy nhiều cặp phương thức, trong đó 1 là phương thức ra lệnh, 1 là phương thức hàm bình thường. Phương thức hàm bình thường sẽ trả lại một đối tượng mới đã được thay đổi dựa trên đối tượng cũ (ví dụ như chuỗi đã được chuyển thành toàn bộ chữ in hoa, hay mảng đã được sắp xếp lại .v.v.). Còn phương thức ra lệnh cũng thực hiện y hệt chức năng thay đổi đó, chỉ khác là thay vì tạo ra một đối tượng mới và trả lại đối tượng mới đó sau khi được gọi, phương thức ra lệnh tác động trực tiếp lên đối tượng gốc.
Ví dụ thường thấy của các cặp phương thức kiểu này gồm có: sort/sort! dùng cho mảng, upcase/upcase! dùng cho chuỗi, chomp/chomp! dùng cho chuỗi và reverse/reverse! dùng cho chuỗi và mảng. Tóm lại là nếu bạn gọi phương thức hàm thông thường, bạn sẽ nhận lại một đối tượng mới và đối tượng gốc không bị thay đổi. Còn khi gọi phương thức ra lệnh, không có đối tượng mới sinh ra mà chính đối tượng gốc bị thay đổi.
Chú thích của người dịch: Diễn giải thì có vẻ lằng nhằng, nhưng các bạn thử ví dụ sau nhé:
a = "hello" puts a.upcase puts a b = "world" puts b b.upcase! puts b
