2009-05-01 38 views
115

Nếu tôi xác định một chức năng của Ruby như thế này:của Ruby thông số tùy chọn

def ldap_get (base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil) 

Làm thế nào tôi có thể gọi nó cung cấp chỉ args đầu tiên 2 và cuối cùng? Tại sao không phải là một cái gì đó như

ldap_get(base_dn, filter, , X) 

hoặc nếu có thể, làm thế nào nó có thể được thực hiện?

Trả lời

122

Hiện tại, điều này không thể xảy ra với ruby. Bạn không thể chuyển các thuộc tính 'trống' sang các phương thức. Gần nhất bạn có thể nhận được là vượt qua nil:

ldap_get(base_dn, filter, nil, X) 

Tuy nhiên, điều này sẽ đặt phạm vi thành không, chứ không phải LDAP :: LDAP_SCOPE_SUBTREE.

Những gì bạn có thể làm là thiết lập giá trị mặc định trong phương pháp của bạn:

def ldap_get(base_dn, filter, scope = nil, attrs = nil) 
    scope ||= LDAP::LDAP_SCOPE_SUBTREE 
    ... do something ... 
end 

Bây giờ nếu bạn gọi phương thức như trên, hành vi sẽ được như bạn mong đợi.

+21

Một chút xíu với phương pháp này: ví dụ: Nếu bạn đang cố gắng làm cho giá trị mặc định cho 'scope' true và bạn vượt qua trong' false', 'scope || = true' sẽ không hoạt động. Nó đánh giá giống như 'nil' và sẽ đặt nó thành' true' –

+4

là có thể với phiên bản ruby ​​hiện tại, 3 năm sau câu trả lời này? – dalloliogm

+1

@ JoshPinter, giải thích tốt đẹp. Về cơ bản || = không phải là a = b hoặc c, tôi co rúm lại khi thấy 'xyz || = true'. Nó nói rằng nếu nó là không, nó luôn luôn đúng. Nếu đó là sự thật, đó là sự thật. –

3

Bạn không thể thực hiện theo cách bạn đã xác định ldap_get. Tuy nhiên, nếu bạn xác định ldap_get như thế này:

def ldap_get (base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE) 

Bây giờ bạn có thể:

ldap_get(base_dn, filter, X) 

Nhưng bây giờ bạn có vấn đề mà bạn không thể gọi nó bằng hai args đầu tiên và arg qua (cùng một vấn đề như trước nhưng bây giờ arg cuối cùng là khác nhau).

Lý do cho việc này rất đơn giản: Mọi đối số trong Ruby không bắt buộc phải có giá trị mặc định, vì vậy bạn không thể gọi nó theo cách bạn đã chỉ định. Trong trường hợp của bạn, ví dụ, hai đối số đầu tiên không có giá trị mặc định.

134

Bạn gần như luôn sử dụng băm tùy chọn tốt hơn.

def ldap_get(base_dn, filter, options = {}) 
    options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE 
    ... 
end 

ldap_get(base_dn, filter, :attrs => X) 
+23

Một chiến lược chung là có một tùy chọn mặc định băm và hợp nhất trong bất cứ điều gì đã được thông qua trong: 'options = default_options.merge (options)' –

+4

Tôi không khuyến khích điều này vì các tùy chọn không cho bạn biết phương thức mong đợi hoặc giá trị mặc định là –

0

Có thể :) Chỉ cần thay đổi định nghĩa

def ldap_get (base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil) 

để

def ldap_get (base_dn, filter, *param_array, attrs=nil) 
scope = param_array.first || LDAP::LDAP_SCOPE_SUBTREE 

phạm vi sẽ được hiện nay trong mảng trên vị trí đầu tiên của nó. Khi bạn cung cấp 3 đối số, sau đó bạn sẽ có giao base_dn, lọc và attrs và param_array sẽ [] Khi 4 và tranh luận nhiều hơn thì param_array sẽ [argument1, or_more, and_more]

Nhược điểm là ... nó là giải pháp không rõ ràng, thực sự xấu xí. Điều này là để trả lời rằng nó có thể đối số ommit ở giữa chức năng gọi trong ruby ​​:)

Một điều bạn phải làm là viết lại giá trị mặc định của phạm vi.

+3

Giải pháp này hoàn toàn sai. Đó là một lỗi cú pháp để sử dụng một tham số giá trị mặc định ('attrs = nil') sau một ký hiệu (' * param_array'). –

+3

-1: Erik là chính xác. Gây ra lỗi cú pháp trong irb 2.0.0p247. Theo _Ngôn ngữ lập trình Ruby_, trong Ruby 1.8, tham số splat phải là cuối cùng ngoại trừ '& parameter', nhưng trong Ruby 1.9 nó có thể được theo sau bởi" thông số bình thường ". Trong trường hợp không phải là một tham số với một pháp lý mặc định sau một tham số với một splat. – andyg0808

+0

Trang Ngôn ngữ lập trình Ruby 186/187 biểu tượng là tốt để sử dụng với các phương thức. Nó phải là tham số cuối cùng trong phương thức trừ khi & được sử dụng. – rupweb

0

Gần đây tôi đã tìm thấy một cách để giải quyết vấn đề này. Tôi muốn tạo một phương thức trong lớp mảng với tham số tùy chọn, để giữ hoặc loại bỏ các phần tử trong mảng.

Cách tôi mô phỏng điều này là bằng cách truyền một mảng làm tham số và sau đó kiểm tra xem giá trị tại chỉ mục đó có phải là không hay không.

class Array 
    def ascii_to_text(params) 
    param_len = params.length 
    if param_len > 3 or param_len < 2 then raise "Invalid number of arguments #{param_len} for 2 || 3." end 
    bottom = params[0] 
    top  = params[1] 
    keep = params[2] 
    if keep.nil? == false 
     if keep == 1 
     self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end} 
     else 
     raise "Invalid option #{keep} at argument position 3 in #{p params}, must be 1 or nil" 
     end 
    else 
     self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact 
    end 
    end 
end 

Cố gắng ra phương pháp lớp học của chúng tôi với các thông số khác nhau:

array = [1, 2, 97, 98, 99] 
p array.ascii_to_text([32, 126, 1]) # Convert all ASCII values of 32-126 to their chr value otherwise keep it the same (That's what the optional 1 is for) 

đầu ra: ["1", "2", "a", "b", "c"]

Được rồi, mát mẻ mà làm việc theo kế hoạch. Bây giờ chúng ta hãy kiểm tra và xem điều gì xảy ra nếu chúng ta không truyền vào tùy chọn tham số thứ ba (1) trong mảng.

array = [1, 2, 97, 98, 99] 
p array.ascii_to_text([32, 126]) # Convert all ASCII values of 32-126 to their chr value else remove it (1 isn't a parameter option) 

đầu ra: ["a", "b", "c"]

Như bạn thấy, tùy chọn thứ ba trong mảng đã được gỡ bỏ, do đó bắt đầu một phần khác nhau trong phương pháp và loại bỏ tất cả các giá trị ASCII không nằm trong phạm vi của chúng tôi (32 -126)

Ngoài ra, chúng tôi có thể đã phát hành giá trị bằng 0 trong các tham số. Hình nào trông giống như khối mã sau:

def ascii_to_text(top, bottom, keep = nil) 
    if keep.nil? 
    self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact 
    else 
    self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end} 
end 
1

1) Bạn không thể quá tải phương thức (Why doesn't ruby support method overloading?) vậy tại sao không viết một phương pháp hoàn toàn mới?

2) Tôi đã giải quyết vấn đề tương tự bằng cách sử dụng toán tử splat * cho một mảng có độ dài bằng 0 hoặc dài hơn. Sau đó, nếu tôi muốn chuyển một tham số (s) tôi có thể, nó được hiểu là một mảng, nhưng nếu tôi muốn gọi phương thức mà không có tham số nào thì tôi không phải truyền bất cứ thứ gì. Xem của Ruby Programming Language trang 186/187

44

Thời gian đã chuyển vào và kể từ phiên bản 2 của Ruby hỗ trợ tên thông số:

def ldap_get (base_dn, filter, scope: "some_scope", attrs: nil) 
    p attrs 
end 

ldap_get("first_arg", "second_arg", attrs: "attr1, attr2") # => "attr1, attr2" 
+0

Bạn cũng có thể sử dụng một splat kép để thu thập thêm đối số từ khóa không xác định. Điều này liên quan đến vấn đề này: http://stackoverflow.com/a/35259850/160363 –

0

Bạn có thể làm điều này với ứng dụng một phần, mặc dù sử dụng các biến tên là chắc chắn dẫn đến nhiều mã có thể đọc được. John Resig viết một bài viết trên blog trong năm 2008 về làm thế nào để làm điều đó trong JavaScript: http://ejohn.org/blog/partial-functions-in-javascript/

Function.prototype.partial = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments); 
    return function(){ 
    var arg = 0; 
    for (var i = 0; i < args.length && arg < arguments.length; i++) 
     if (args[i] === undefined) 
     args[i] = arguments[arg++]; 
    return fn.apply(this, args); 
    }; 
}; 

Nó có lẽ sẽ có thể áp dụng nguyên tắc tương tự trong Ruby (trừ trường hợp thừa kế nguyên chủng).

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