Programming

루비 옵션 매개 변수

procodes 2020. 7. 13. 22:27
반응형

루비 옵션 매개 변수


다음과 같이 Ruby 함수를 정의하면 :

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

처음 2 개와 마지막 인수 만 제공하면 어떻게 호출 할 수 있습니까? 왜 그렇지 않은가

ldap_get( base_dn, filter, , X)

가능하거나 가능하다면 어떻게 할 수 있습니까?


현재 루비에서는 불가능합니다. '빈'속성은 메소드에 전달할 수 없습니다. 당신이 얻을 수있는 가장 가까운 것은 nil을 전달하는 것입니다.

ldap_get(base_dn, filter, nil, X)

그러나 LDAP :: LDAP_SCOPE_SUBTREE가 아니라 범위를 nil로 설정합니다.

할 수있는 일은 메소드 내에서 기본값을 설정하는 것입니다.

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

위와 같이 메소드를 호출하면 예상대로 동작합니다.


거의 항상 옵션 해시를 사용하는 것이 좋습니다.

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

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

버전 2 이후 루비는 명명 된 매개 변수를 지원합니다.

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"

정의한 방식으로 수행 할 수 없습니다 ldap_get. 그러나 다음 ldap_get과 같이 정의 하면

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

이제 다음을 수행 할 수 있습니다.

ldap_get( base_dn, filter, X )

그러나 이제는 처음 두 인수와 마지막 인수로 호출 할 수 없다는 문제가 있습니다 (이전과 동일한 문제이지만 이제 마지막 인수는 다릅니다).

이에 대한 이론적 근거는 간단합니다. Ruby의 모든 인수는 기본값을 가질 필요가 없으므로 지정한 방식으로 호출 할 수 없습니다. 예를 들어, 처음 두 인수에는 기본값이 없습니다.


1) 메소드를 오버로드 할 수 없습니다 ( 루비가 왜 메소드 오버로드를 지원하지 않습니까? ) ? 왜 새로운 메소드를 작성하지 않습니까?

2) 길이가 0 이상인 배열에 대해 splat 연산자 *를 사용하여 비슷한 문제를 해결했습니다. 그런 다음 매개 변수를 전달하려면 배열로 해석되지만 매개 변수없이 메서드를 호출하려면 아무것도 전달할 필요가 없습니다. 참조 루비 언어 프로그래밍 페이지 187분의 186을


최근 에이 문제를 해결할 방법을 찾았습니다. 배열에서 요소를 유지하거나 삭제하기 위해 선택적 매개 변수를 사용하여 배열 클래스에서 메소드를 만들고 싶었습니다.

내가 이것을 시뮬레이션 한 방법은 배열을 매개 변수로 전달한 다음 해당 인덱스의 값이 nil인지 여부를 확인하는 것입니다.

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

다른 매개 변수로 클래스 메소드를 사용해보십시오.

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)

산출: ["1", "2", "a", "b", "c"]

좋아, 멋지게 계획대로 작동합니다. 이제 배열의 세 번째 매개 변수 옵션 (1)을 전달하지 않으면 어떻게되는지 확인하겠습니다.

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)

산출: ["a", "b", "c"]

As you can see, the third option in the array has been removed, thus initiating a different section in the method and removing all ASCII values that are not in our range (32-126)

Alternatively, we could had issued the value as nil in the parameters. Which would look similar to the following code block:

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

It is possible :) Just change definition

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

to

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

scope will be now in array on its first place. When you provide 3 arguments, then you will have assigned base_dn, filter and attrs and param_array will be [] When 4 and more arguments then param_array will be [argument1, or_more, and_more]

Downside is... it is unclear solution, really ugly. This is to answer that it is possible to ommit argument in the middle of function call in ruby :)

Another thing you have to do is to rewrite default value of scope.


You could do this with partial application, although using named variables definitely leads to more readable code. John Resig wrote a blog article in 2008 about how to do it in 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);
  };
};

It would probably be possible to apply the same principle in Ruby (except for the prototypal inheritance).

참고URL : https://stackoverflow.com/questions/812058/ruby-optional-parameters

반응형