Computer >> Máy Tính >  >> Lập trình >> Ruby

Thú vị với các đối số từ khóa, băm và ghép

Bạn có thể đã thấy mẫu này trước đây. Một phương thức có một options băm là đối số cuối cùng của nó, chứa các tham số bổ sung:

def hello_message(name_parts = {})
  first_name = name_parts.fetch(:first_name)
  last_name = name_parts.fetch(:last_name)

  "Hello, #{first_name} #{last_name}"
end

Thật không may, bạn cần phải trích xuất các thông số đó ra khỏi hàm băm. Và điều đó có nghĩa là có rất nhiều thiết lập cần phải vượt qua trước khi bạn đến với phần tốt.

Nhưng nếu bạn đã thay đổi phương pháp này để sử dụng các đối số từ khóa trong Ruby 2.0+, bạn sẽ không phải kéo :first_name:last_name ra khỏi hàm băm của bạn. Ruby làm điều đó cho bạn:

def hello_message(first_name:, last_name:)
  "Hello, #{first_name} #{last_name}"
end

Tốt hơn nữa, nếu ứng dụng của bạn sử dụng cú pháp băm Ruby 1.9+, các phương thức của bạn có thể sử dụng các đối số từ khóa mà không thay đổi trình gọi của các phương thức đó:

def hello_message_with_an_options_hash(name_parts = {})
  first_name = name_parts.fetch(:first_name)
  last_name = name_parts.fetch(:last_name)

  "Hello, #{first_name} #{last_name}"
end

def hello_message_with_keyword_arguments(first_name:, last_name:)
  "Hello, #{first_name} #{last_name}"
end

hello_message_with_an_options_hash(first_name: "Justin", last_name: "Weiss")

hello_message_with_keyword_arguments(first_name: "Justin", last_name: "Weiss")

Nhìn thấy? Các đối số đó giống hệt nhau!

Đẩy cú pháp đối số từ khóa lên quá xa một bước

Điều gì xảy ra nếu bạn chưa đã chuyển sang cú pháp Hash mới? Bạn có thể chuyển đổi tất cả mã của mình. Nhưng, ít nhất trong Ruby 2.2.1, cái cú pháp băm hoạt động tốt với các đối số từ khóa:

irb(main):007:0> hello_message_with_keyword_arguments(:first_name => "Justin", :last_name => "Weiss")
=> "Hello, Justin Weiss"

Tốt đẹp! Điều gì về việc chuyển một đối tượng băm , thay vì đối số?

irb(main):008:0> options = {:first_name => "Justin", :last_name => "Weiss"}
irb(main):009:0> hello_message_with_keyword_arguments(options)
=> "Hello, Justin Weiss"

Ái chà. Điều gì sẽ xảy ra nếu chúng ta muốn trộn một đối số băm và từ khóa?

irb(main):010:0> options = {last_name: "Weiss"}
irb(main):011:0> hello_message_with_keyword_arguments(first_name: "Justin", options)
SyntaxError: (irb):11: syntax error, unexpected ')', expecting =>
	from /usr/local/bin/irb:11:in `<main>'

ĐƯỢC RỒI. Tôi đoán chúng ta đã đi một bước quá xa. Để khắc phục điều này, bạn có thể sử dụng Hash # merge để tạo một hàm băm mà bạn có thể tự chuyển vào. Nhưng có một cách tốt hơn.

Nếu bạn đang sử dụng các đối số thông thường thay vì các đối số từ khóa, bạn có thể tách các đối số từ Mảng, bằng cách sử dụng * :

def generate_thumbnail(name, width, height)
  # ...
end

dimensions = [240, 320]
generate_thumbnail("headshot.jpg", *dimensions)

Nhưng có cách nào để hiển thị từ khóa đối số vào danh sách đối số?

Hóa ra là:** . Đây là cách bạn sửa ví dụ bị hỏng đó với ** :

irb(main):010:0> options = {last_name: "Weiss"}
irb(main):011:0> hello_message_with_keyword_arguments(first_name: "Justin", **options)
=> "Hello, Justin Weiss"

Và nếu bạn thực sự điên rồ, bạn có thể kết hợp các đối số thông thường, đối số từ khóa và biểu tượng:

def hello_message(greeting, time_of_day, first_name:, last_name:)
  "#{greeting} #{time_of_day}, #{first_name} #{last_name}!"
end

args = ["Morning"]
keyword_args = {last_name: "Weiss"}

hello_message("Good", *args, first_name: "Justin", **keyword_args) # => "Good Morning, Justin Weiss!"

Tất nhiên, nếu bạn thấy mình ở trong tình huống cần thiết, có lẽ bạn đã mắc sai lầm sớm hơn rất nhiều!

Nắm bắt các đối số từ khóa một cách dễ dàng

Bạn có biết cách bạn có thể chuyển tất cả các đối số phương thức của mình thành một mảng bằng cách sử dụng * ?

def argument_capturing_method(*args)
  args
end

argument_capturing_method(1, 2, 3) # => [1, 2, 3]

Điều này cũng hoạt động với các đối số từ khóa. Chúng được chuyển đổi thành hàm băm và hiển thị dưới dạng đối số cuối cùng của args của bạn mảng:

argument_capturing_method(1, 2, 3, key: "value") # => [1, 2, 3, {:key=>"value"}]

Nhưng args.last[:key] không phải là cách tốt nhất để đọc các đối số từ khóa được nắm bắt theo cách này. Thay vào đó, bạn có thể sử dụng ** mới cú pháp để tự nhận các đối số từ khóa:

def dual_argument_capturing_method(*args, **keyword_args)
  {args: args, keyword_args: keyword_args}
end

dual_argument_capturing_method(1, 2, 3, key: "value") # => {:args=>[1, 2, 3], :keyword_args=>{:key=>"value"}}

Với cú pháp này, bạn có thể truy cập đối số chính quy đầu tiên bằng args[0]:key đối số từ khóa với keyword_args[:key] .

… Tất nhiên, bây giờ chúng ta quay lại với các hàm băm tùy chọn.

Các đối số từ khóa rất tốt để loại bỏ hàng tấn bảng soạn sẵn trích xuất tham số khỏi mã của bạn. Và bạn thậm chí có thể không phải thay đổi bất kỳ mã nào của mình để tận dụng chúng.

Nhưng khi bạn viết các phương pháp chung chung hơn, có một số kỹ thuật mới bạn sẽ phải học để xử lý tốt các đối số từ khóa. Bạn có thể không phải sử dụng những kỹ thuật đó thường xuyên. Nhưng khi bạn làm vậy, sức mạnh và sự linh hoạt này sẽ ở đó, chờ đợi bạn.