Các tham số tùy chọn của Ruby


121

Nếu tôi định nghĩa một hàm Ruby như thế này:

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ó là chỉ cung cấp 2 args đầu tiên và cuối cùng? Tại sao cái gì đó không giống như

ldap_get( base_dn, filter, , X)

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

Câu trả lời:


131

Điều này hiện không thể thực hiện được với ruby. Bạn không thể chuyển các thuộc tính 'trống' cho các phương thức. Gần nhất bạn có thể đạt đượ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 nil, không phải LDAP :: LDAP_SCOPE_SUBTREE.

Những gì bạn có thể làm là đặt giá trị mặc định trong phương thức 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ẽ như bạn mong đợi.


21
Một chút hiểu biết với phương pháp này: ví dụ: Nếu bạn đang cố đặt giá trị mặc định cho scopetrue và bạn chuyển vào false, scope ||= truesẽ không hoạt động. Nó đánh giá giống như nilvà sẽ đặt nó vàotrue
Joshua Pinter

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

1
@JoshPinter, lời giải thích hay. Về cơ bản || = không phải là a = b hay c, tôi co rúm người khi nhìn thấy xyz||=true. Nó nói nếu nó không, nó luôn luôn đúng. Nếu nó là sự thật, nó là sự thật.
Damon Aw

7
Mọi người đều nói rằng nó tồi tệ như thế nào scope ||= true, tôi ngạc nhiên là không ai đề cập rằng cách tốt hơn để làm điều này là với scope = LDAP::LDAP_SCOPE_SUBTREE if scope.nil?. Tất nhiên, ngay cả khi giả định đó nillà một giá trị không hợp lệ.
Erik Sandberg

1
Cập nhật cho phiên bản cũ này: Một giải pháp thay thế là sử dụng ký hiệu gạch dưới. Thật không may, nó có tác dụng tương tự như cài đặt tham số nil. Một số có thể thích ký hiệu: ldap_get(base_dn, filter, _, X)(lưu ý: Tôi không biết (chưa) khi nào điều này được giới thiệu trong Ruby. Chuỗi SO thú vị ).
Eric Platon

137

Bạn hầu như luôn luôn tốt hơn khi sử dụng hàm băm tùy chọ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à phải 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:options = default_options.merge(options)
Nathan dài

7
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 những gì mong đợi phương pháp hoặc những gì các giá trị mặc định là
Bron Davies

53

Thời gian đã trôi qua và kể từ phiên bản 2 Ruby hỗ trợ các tham số có tên:

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"

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

3

Không thể thực hiện theo cách bạn đã xác định ldap_get. Tuy nhiên, nếu bạn định nghĩa ldap_getnhư 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ó một vấn đề là bạn không thể gọi nó với hai đối số đầu tiên và đối số cuối cùng (cùng một vấn đề như trước nhưng đối số cuối cùng đã khác).

Cơ sở lý luận cho điều 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, chẳng hạn, hai đối số đầu tiên không có giá trị mặc định.


1

1) Bạn không thể nạp chồng phương thức ( Tại sao ruby ​​không hỗ trợ nạp chồng phương thức? ) Vậy tại sao không viết một phương thức mới hoàn toàn?

2) Tôi đã giải quyết mộ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 trở lên. Sau đó, nếu tôi muốn truyền (các) tham số thì 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ó bất kỳ tham số nào thì tôi không phải truyền bất kỳ thứ gì. Xem Ngôn ngữ lập trình Ruby trang 186/187


0

Gần đây tôi đã tìm ra 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 một 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 chuyể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à nil 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

Đang thử phương thức lớp của chúng tôi với các tham 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, thật tuyệt. Bây giờ hãy kiểm tra và xem điều gì sẽ 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 có thể thấy, tùy chọn thứ ba trong mảng đã bị xóa, do đó bắt đầu một phần khác trong phương thức và xóa 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ể đã đưa ra giá trị là nil trong các tham số. Khối nào trông giống với 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

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

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

đến

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

phạm vi bây giờ sẽ nằm trong mảng ở vị trí đầu tiên của nó. Khi bạn cung cấp 3 đối số, thì bạn sẽ gán base_dn, filter và attrs và param_array sẽ là [] Khi 4 đối số trở lên thì param_array sẽ là [đối số1, hoặc_more, và_more]

Nhược điểm là ... đó 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 có thể bỏ qua đối số ở giữa lệnh gọi hàm trong ruby ​​:)

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


4
Giải pháp này là hoàn toàn sai lầm. Đó là một lỗi cú pháp khi sử dụng một tham số giá trị mặc định ( attrs=nil) sau một splat ( *param_array).
Erik Sandberg

3
-1: Erik đúng. 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 đứng sau cùng ngoại trừ một &parameter, nhưng trong Ruby 1.9, nó cũng có thể được theo sau bởi "tham số thông thường". Trong cả hai trường hợp đều không phải là một tham số có giá trị pháp lý mặc định sau một tham số có biểu tượng.
andyg0808

Ngôn ngữ lập trình Ruby trang 186/187 biểu tượng được 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

Vì vậy, AndyG đã đúng, thứ tự cần phải là: def ldap_get (base_dn, filter, attrs = nil, * param_array)
rupweb Ngày

-1

Bạn có thể làm điều này với ứng dụng một phần, mặc dù việc sử dụng các biến được đặt tên chắc chắn dẫn đến mã dễ đọc hơn. John Resig đã viết một bài báo trên blog vào năm 2008 về cách thực hiện nó 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);
  };
};

Có thể áp dụng nguyên tắc tương tự trong Ruby (ngoại trừ kế thừa nguyên mẫu).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.