루비를 조금 엉망으로 만들려고합니다. 그래서 나는 책 “Programming Collective Intelligence”Ruby의 알고리즘 (Python으로 제공)을 구현하려고합니다.
8 장에서 저자는 메소드 a를 매개 변수로 전달합니다. 이것은 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)
답변
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
이와 같은 블록 선언에서 기본 인수를 설정할 수 없습니다. 따라서 splat을 사용하고 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
그러나 여기에 더 많은 재사용 가능한 코드 덩어리를 원하시는 것 같습니다.
답변
블록과 Procs를 언급하는 주석은 Ruby에서 더 일반적이라는 점에서 정확합니다. 그러나 원하는 경우 메서드를 전달할 수 있습니다. 당신은 전화 method
방법을 얻을하고 .call
그것을 전화 :
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
답변
방법으로 매개 변수로 메소드를 전달할 수 있습니다 method(:function)
. 다음은 매우 간단한 예입니다.
def double (a) * 2 반환 종료 => 없음 def method_with_function_as_param (콜백, 번호) callback.call (번호) 종료 => 없음 method_with_function_as_param (method (: double), 10) => 20
답변
이를 수행하는 일반적인 Ruby 방법은 블록을 사용하는 것입니다.
따라서 다음과 같습니다.
def weightedknn( data, vec1, k = 5 )
foo
weight = yield( dist )
foo
end
그리고 다음과 같이 사용됩니다.
weightenknn( data, vec1 ) { |dist| gaussian( dist ) }
이 패턴은 Ruby에서 광범위하게 사용됩니다.
답변
메서드 인스턴스 에서 &
연산자를 사용하여 메서드를 블록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에서
답변
함수 객체의 “call”메소드를 호출해야합니다.
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
Afterwerds, 다음과 같이이 함수를 호출 할 수 있습니다.
@contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == @current_user
end
선택 항목을 필터링 할 필요가 없으면 블록을 생략하면됩니다.
@categories = make_select_list( Category ) # selects all categories
Ruby 블록의 힘을 위해 너무나 많이.