2013-02-25 27 views
10

Ruby 2.0.0 hỗ trợ đối số từ khóa (KA) và tôi tự hỏi những lợi ích/trường hợp sử dụng của tính năng này trong bối cảnh của Ruby thuần túy, đặc biệt là khi nhìn thấy trong ánh sáng của hiệu suất phạt do từ khóa phù hợp mà cần phải được thực hiện mỗi khi một phương pháp với các đối số từ khóa được gọi là.Khi sử dụng các đối số từ khóa được gọi là tham số trong Ruby

require 'benchmark' 

def foo(a:1,b:2,c:3) 
    [a,b,c] 
end 

def bar(a,b,c) 
    [a,b,c] 
end 

number = 1000000 
Benchmark.bm(4) do |bm| 
    bm.report("foo") { number.times { foo(a:7,b:8,c:9) } } 
    bm.report("bar") { number.times { bar(7,8,9) } } 
end 

#   user  system  total  real 
# foo 2.797000 0.032000 2.829000 ( 2.906362) 
# bar 0.234000 0.000000 0.234000 ( 0.250010) 

Trả lời

1

Ví dụ

Một chức năng

def welcome_message(message, options={}) 
    default_options = {name: 'hoge'} 
    options = default_options.merge(options) 

    "#{message}、#{options[:name]}" 
end 

có thể được viết

def welcome_message(message, name: 'hoge') 
    "#{message}、#{name}" 
end 
+0

Để thêm vào câu trả lời, hãy sử dụng chúng khi bạn cần gán các đối số cho các biến bên trong định nghĩa phương thức của bạn và tránh tự viết mã tùy chỉnh. – Kashyap

+0

Xin đừng lừa chúng tôi. 'def welcome_message (message, options = {: name => 'hoge'}); "# {message} 、 # {options [: name]}"; end' là một lớp lót cho 'welcome_message'. Nhược điểm chính của phương pháp này, mặc dù, là một trong hai cần phải mở rộng 'Hash' với kinda' key_valid? 'Hoặc hy vọng rằng các phím thông qua là chính xác. Cách tiếp cận KA cho phép xác định chính xác các phím nào được cho phép. – mudasobwa

+1

@mudasobwa Dường như với tôi bạn đã sai; với hàm của bạn, 'welcome_message (" message ", {: age => 22})' sẽ không hiển thị 'hoge' trong kết quả mà sẽ sử dụng' keyword'. Hàm bạn đặt giá trị mặc định cho toàn bộ băm, không phải là giá trị mặc định cho khóa được xác định của băm. – oldergod

3

Kể từ KA là đổi mới ruby-rộng, tôi thấy hai ưu điểm chính:

  • giới hạn các đối số được phép đối với một tập hợp được xác định trước, như Rails thực hiện với assert_valid_keys;
  • sử dụng tính năng trong các khối mã.

Các tổng hợp lên:

a = lambda { |name: "Leonardo", age: 67| [name, age] } 
a.call # ⇒ ["Leonardo", 67] 
a.call name: "Michelangelo", age: 88 # ⇒ ["Michelangelo", 88] 
a.call name: "Schwarzenegger", alive: true # ⇒ ArgumentError: unknown keyword: alive 
10

đối số từ khóa có một vài lợi thế riêng biệt không ai đề cập đến.

Trước hết bạn không được ghép nối với thứ tự của các đối số. Vì vậy, trong trường hợp bạn có thể có một cuộc tranh luận nil thỉnh thoảng nó trông rất sạch:

def yo(sup, whats="good", dude="!") 
    # do your thing 
end 

yo("hey", nil, "?") 

nếu bạn sử dụng đối số từ khóa:

def yo(sup:, whats:"good", dude:"!") 
    # do your thing 
end 

yo(sup: "hey", dude: "?") 

hoặc thậm chí

yo(dude: "?", sup: "hey") 

Nó loại bỏ các cần phải nhớ thứ tự của các đối số. Tuy nhiên, bất lợi là bạn phải nhớ tên của đối số, nhưng điều đó nên ít nhiều trực quan.

Ngoài ra, khi bạn có một phương pháp có thể có thể cần phải có nhiều đối số hơn trong tương lai.

def create_person(name:, age:, height:) 
    # make yourself some friends 
end 

gì xảy ra nếu hệ thống của bạn tất cả các đột ngột muốn biết về thanh kẹo yêu thích của một người, hoặc nếu họ bị thừa cân (từ tiêu thụ quá nhiều thanh kẹo yêu thích của họ), làm thế nào bạn sẽ làm điều đó? Đơn giản:

def create_person(name:, age:, height:, favorite_candy:, overweight: true) 
    # make yourself some fat friends 
end 

Trước khi đối số từ khóa luôn có hàm băm, nhưng điều đó dẫn đến nhiều mã mẫu soạn sẵn hơn để trích xuất và gán biến. Mã Boilerplate == nhập nhiều hơn == nhiều lỗi đánh máy tiềm năng == ít lần viết mã ruby ​​tuyệt vời.

def old_way(name, opts={}) 
    age = opts[:age] 
    height = opts[:height] 
    # all the benefits as before, more arthritis and headaches 
end 

Nếu bạn chỉ thiết lập một phương pháp mà phải mất một đối số và sẽ hầu như không bao giờ có nhu cầu thay đổi:

def say_full_name(first_name, last_name) 
    puts "#{first_name} #{last_name}" 
end 

luận Rồi từ khóa nên tránh, vì có một buổi biểu diễn nhỏ đánh.

3

Vấn đề không hiệu quả khi sử dụng đối số từ khóa không còn có vẻ là vấn đề như của ruby-2.2.0.

Feature #10440 khắc phục sự cố tốc độ và được phát hành vào ruby-2.2.0:

Mon 03 tháng 11 03:02:38 2014 Koichi Sasada

  • phương pháp viết lại/tham số khối phù hợp logic để tối ưu hóa đối số từ khóa/các tham số và đối số splat. Feature #10440 (Chi tiết được mô tả trong vé này)

Bạn có thể thấy điều này cho chính mình (sử dụng cùng mã như được đưa ra trong câu hỏi ban đầu):

(08:04:%) rvm use ruby-2.0.0-p247 
Using /Users/adam/.rvm/gems/ruby-2.0.0-p247 

(08:04:%) ruby keyword_benchmarks.rb 

     user  system  total  real 
foo 1.390000 0.060000 1.450000 ( 1.451284) 
bar 0.130000 0.000000 0.130000 ( 0.122344) 

(08:04:%) rvm use ruby-2.2.0 
Using /Users/adam/.rvm/gems/ruby-2.2.0 

(08:04:%) ruby keyword_benchmarks.rb 

     user  system  total  real 
foo 0.140000 0.000000 0.140000 ( 0.136194) 
bar 0.110000 0.000000 0.110000 ( 0.116246) 

Vẫn còn một hình phạt hiệu suất cực kỳ không đáng kể để sử dụng từ khóa args, nhưng tôi nghĩ rằng đó là một sự cân bằng chấp nhận được để đổi lấy lợi ích của việc tăng khả năng đọc và linh hoạt vị trí.

Các vấn đề liên quan