programing

Ruby에서 메서드를 매개 변수로 전달

topblog 2023. 6. 2. 20:04
반응형

Ruby에서 메서드를 매개 변수로 전달

루비랑 좀 놀리려고요.그래서 저는 "프로그래밍 집단지성" 루비라는 책의 알고리즘(파이썬에서 제공)을 구현하려고 노력합니다.

8장에서 작성자는 메소드를 매개 변수로 전달합니다.이것은 Python에서 작동하는 것처럼 보이지만 Ruby에서는 작동하지 않습니다.

방법은 여기 있습니다.

def gaussian(dist, sigma=10.0)
  foo
end

그리고 이것을 다른 방법으로 부르고 싶습니다.

def weightedknn(data, vec1, k = 5, weightf = gaussian)
  foo
  weight = weightf(dist)
  foo
end

내게 주어진 것은 오류뿐입니다.

ArgumentError: wrong number of arguments (0 for 1)

블록과 Procs에 대한 언급은 루비에서 더 일반적이라는 점에서 정확합니다.하지만 당신이 원한다면 방법을 통과할 수 있습니다.이 출호에게 하세요.method과 법과방을 .call그것을 부르는 말:

def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
  ...
  weight = weightf.call( dist )
  ...
end

proc 개체를 원하는 경우:

gaussian = Proc.new do |dist, *args|
  sigma = args.first || 10.0
  ...
end

def weightedknn(data, vec1, k = 5, weightf = gaussian)
  ...
  weight = weightf.call(dist)
  ...
end

그런 블록 선언에서는 기본 인수를 설정할 수 없습니다.따라서 스플랫을 사용하여 proc 코드 자체에 기본값을 설정해야 합니다.


또는 사용자의 범위에 따라 메서드 이름을 전달하는 것이 더 쉬울 수 있습니다.

def weightedknn(data, vec1, k = 5, weightf = :gaussian)
  ...
  weight = self.send(weightf)
  ...
end

이 경우 전체 코드 청크를 전달하는 것이 아니라 객체에 정의된 메서드를 호출하는 것입니다. 구성하느냐에 해야 할 수도 .self.send와 함께object_that_has_the_these_math_methods.send


마지막으로 중요한 것은, 당신은 그 방법을 차단할 수 있다는 것입니다.

def weightedknn(data, vec1, k = 5)
  ...
  weight = 
    if block_given?
      yield(dist)
    else
      gaussian.call(dist)
    end
  end
  ...
end

weightedknn(foo, bar) do |dist|
  # square the dist
  dist * dist
end

하지만 당신은 더 많은 재사용 가능한 코드 덩어리를 원할 것으로 보입니다.

할 수 .method(:function)방법. 아래는 매우 간단한 예입니다.

디프 더블(a)* 2를 반환합니다.끝.=> 0
def method_with_function_as_param(콜백, 번호)callback.call(번호)끝.=> 0
method_with_function_as_param(method(:double), 10 )=> 20

일반적인 Ruby 방법은 블록을 사용하는 것입니다.

그래서 다음과 같은 것이는 다음과 같습니다.

def weightedknn(data, vec1, k = 5)
  foo
  weight = yield(dist)
  foo
end

다음과 같이 사용됩니다.

weightedknn(data, vec1) { |dist| gaussian( dist ) }

이 패턴은 루비에서 많이 사용됩니다.

당신은 할 수 .&Method메서드를 블록으로 변환하는 메서드의 인스턴스입니다.

예:

def foo(arg)
  p arg
end

def bar(&block)
  p 'bar'
  block.call('foo')
end

bar(&method(:foo))

자세한 내용은 http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html 에서 확인하십시오.

함수 개체의 메서드를 "호출"이라고 불러야 합니다.

weight = weightf.call( dist )

편집: 코멘트에서 설명한 것처럼, 이 접근 방식은 잘못되었습니다.정상적인 기능 대신에 Procs를 사용한다면 작동할 것입니다.

함수 내에서 명명된 블록에 액세스하려면 앰퍼샌드를 사용하는 것이 좋습니다. 기사의 권장 사항에 따라 다음과 같은 내용을 작성할 수 있습니다(이것은 제 작업 프로그램의 실제 스크랩입니다).

  # Returns a valid hash for html form select element, combined of all entities
  # for the given +model+, where only id and name attributes are taken as
  # values and keys correspondingly. Provide block returning boolean if you
  # need to select only specific entities.
  #
  # * *Args*    :
  #   - +model+ -> ORM interface for specific entities'
  #   - +&cond+ -> block {|x| boolean}, filtering entities upon iterations
  # * *Returns* :
  #   - hash of {entity.id => entity.name}
  #
  def make_select_list( model, &cond )
    cond ||= proc { true } # cond defaults to proc { true }
    # Entities filtered by cond, followed by filtration by (id, name)
    model.all.map do |x|
      cond.( x ) ? { x.id => x.name } : {}
    end.reduce Hash.new do |memo, e| memo.merge( e ) end
  end

Words 후에 다음 함수를 호출할 수 있습니다.

@contests = make_select_list Contest do |contest|
  logged_admin? or contest.organizer == @current_user
end

선택 항목을 필터링할 필요가 없으면 다음 블록을 생략합니다.

@categories = make_select_list( Category ) # selects all categories

루비 블록의 힘은 여기까지입니다.

Proc 또는 메서드 호출과 유사하게 람다를 다음과 같이 전달할 수도 있습니다.weightf매개 변수:

def main
  gaussian = -> (params) {
    ...
  }
  weightedknn(data, vec1, k = 5, gaussian, params)
  # Use symbol :gaussian if method exists instead
end

def weightedknn(data, vec1, k = 5, weightf, params)
  ...
  weight = weightf.call(params)
  ...
end

또한 "eval"을 사용하여 메소드를 문자열 인수로 전달한 다음 다른 메소드로 간단히 평가할 수 있습니다.

언급URL : https://stackoverflow.com/questions/522720/passing-a-method-as-a-parameter-in-ruby

반응형