Ruby 선택적 매개 변수


121

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

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

처음 2 개와 마지막 인수 만 제공하여 어떻게 호출 할 수 있습니까? 왜 그런 게 아니야

ldap_get( base_dn, filter, , X)

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

답변:


131

현재 루비로는 불가능합니다. '빈'속성을 메소드에 전달할 수 없습니다. 얻을 수있는 가장 가까운 방법은 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

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


21
이 방법 약간 잡았다 : 예를 들어, 당신의 기본값 만들려고 노력하는 경우 scope사실을 당신이에 통과 false, scope ||= true일을하지 않습니다. 그것은 다음과 동일하게 평가되고 nil설정 될 것입니다true
Joshua Pinter

4
이 답변 후 3 년이 지난 현재 버전의 루비로 가능합니까?
dalloliogm

1
@JoshPinter, 좋은 설명. 기본적으로 || =는 a = b 또는 c가 아니므로 xyz||=true. 그것이 0이면 항상 사실이라는 것입니다. 그것이 사실이라면 그것은 사실입니다.
Damon Aw

7
모두가 얼마나 나쁜지 말하면서 scope ||= true,이 작업을 수행하는 더 좋은 방법이 scope = LDAP::LDAP_SCOPE_SUBTREE if scope.nil?. 물론 그것이 nil잘못된 값 이라고 가정하는 것 입니다.
Erik Sandberg 2013 년

1
이 구식 업데이트 : 대안은 밑줄 표기법을 사용하는 것입니다. 안타깝게도 매개 변수를로 설정하는 것과 동일한 효과가 nil있습니다. 어떤 사람들은 다음과 같은 표기법을 좋아할 것입니다 : ldap_get(base_dn, filter, _, X)(참고 : 이것이 Ruby에 언제 도입되었는지 (아직) 모릅니다. 흥미로운 SO 스레드 ).
Eric Platon 2014 년

137

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

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

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

23
일반적인 전략은 기본 옵션을 해시하고 전달 된 내용을 병합하는 것입니다.options = default_options.merge(options)
Nathan Long

7
옵션은 기본값이 무엇 메소드 예상하는 또는 무엇을 말하지 않기 때문에 나는이 낙담
브롱 데이비스

53

시간이 지났고 버전 2 이후 Ruby는 명명 된 매개 변수를 지원합니다.

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
이중 표시를 사용하여 정의되지 않은 추가 키워드 인수를 수집 할 수도 있습니다. 이것은이 문제와 관련이 있습니다. stackoverflow.com/a/35259850/160363
Henry Tseng

3

정의한 방식으로 할 수 없습니다 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

1) 메서드를 오버로드 할 수 없습니다 ( 루비가 메서드 오버로딩을 지원하지 않는 이유는 무엇입니까? ). 새로운 메서드를 모두 작성 하지 않는 이유는 무엇 입니까?

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


0

최근에 나는 이것에 대한 방법을 찾았습니다. 선택적 매개 변수를 사용하여 배열 클래스에 메서드를 만들어 배열의 요소를 유지하거나 버리고 싶었습니다.

이것을 시뮬레이션 한 방법은 배열을 매개 변수로 전달한 다음 해당 인덱스의 값이 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"]

보시다시피 배열의 세 번째 옵션이 제거되었으므로 메서드에서 다른 섹션을 시작하고 범위 (32-126)에없는 모든 ASCII 값을 제거합니다.

또는 매개 변수에서 값을 nil로 발행 할 수 있습니다. 다음 코드 블록과 유사합니다.

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

가능합니다 :) 정의 변경

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

범위는 이제 처음에 배열됩니다. 3 개의 인수를 제공하면 base_dn, filter 및 attrs가 할당되고 param_array는 []가됩니다. 4 개 이상의 인수가 있으면 param_array는 [argument1, or_more, and_more]가됩니다.

단점은 ... 불명확 한 해결책이고 정말 추합니다. 이것은 루비에서 함수 호출 도중 인수를 생략 할 수 있다는 대답입니다. :)

해야 할 또 다른 일은 범위의 기본값을 다시 작성하는 것입니다.


4
이 솔루션은 완전히 잘못되었습니다. attrs=nil표시 ( *param_array) 뒤에 기본값 매개 변수 ( ) 를 사용하는 것은 구문 오류 입니다.
Erik Sandberg 2013 년

3
-1 : Erik이 맞습니다. irb 2.0.0p247에서 구문 오류가 발생합니다. Ruby 프로그래밍 언어 에 따르면 Ruby 1.8에서는 splat 매개 변수가를 제외하고 마지막에 있어야 &parameter하지만 Ruby 1.9에서는 "일반 매개 변수"가 뒤따를 수도 있습니다. 두 경우 모두 표시가있는 매개 변수 뒤에 기본적으로 유효한 매개 변수가 없었습니다.
andyg0808 2013 년

Ruby Programming Language 페이지 186/187은 메소드와 함께 사용하는 것이 좋습니다. &를 사용하지 않는 한 메서드의 마지막 매개 변수 여야합니다.
rupweb

그래서 AndyG가 맞습니다. 순서는 다음과 같아야합니다. def ldap_get (base_dn, filter, attrs = nil, * param_array)
rupweb

-1

명명 된 변수를 사용하면 코드를 더 읽기 쉽게 만들 수 있지만 부분 응용 프로그램으로이 작업을 수행 할 수 있습니다. John Resig는 2008 년에 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);
  };
};

Ruby에서도 동일한 원칙을 적용하는 것이 가능할 것입니다 (프로토 티팔 상속 제외).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.