Ruby에서 map (& : method) 구문에 인수를 제공 할 수 있습니까?
다음 Ruby 속기 ( a
is an array)에 익숙 할 것입니다 .
a.map(&:method)
예를 들어, irb에서 다음을 시도하십시오.
>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]
구문 a.map(&:class)
은 a.map {|x| x.class}
.
" Ruby에서 map (& : name)은 무엇을 의미합니까? " 에서이 구문에 대해 자세히 읽어보십시오 .
구문을 통해 각 배열 요소에 대해 &:class
메서드를 호출 class
합니다.
내 질문은 : 메서드 호출에 인수를 제공 할 수 있습니까? 그렇다면 어떻게?
예를 들어, 다음 구문을 어떻게 변환합니까?
a = [1,3,5,7,9]
a.map {|x| x + 2}
받는 사람 &:
구문?
나는 &:
구문이 더 낫다는 것을 제안하지 않습니다 . 나는 &:
인수와 함께 구문 을 사용하는 메커니즘에 관심이 있습니다.
+
Integer 클래스의 메서드 라는 것을 알고 있다고 가정합니다 . irb에서 다음을 시도 할 수 있습니다.
>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2
다음 Symbol
과 같이 간단한 패치를 만들 수 있습니다 .
class Symbol
def with(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
이를 통해 다음을 수행 할 수 있습니다.
a = [1,3,5,7,9]
a.map(&:+.with(2))
# => [3, 5, 7, 9, 11]
그러나 여러 매개 변수를 전달하는 것과 같은 많은 다른 멋진 기능도 있습니다.
arr = ["abc", "babc", "great", "fruit"]
arr.map(&:center.with(20, '*'))
# => ["********abc*********", "********babc********", "*******great********", "*******fruit********"]
arr.map(&:[].with(1, 3))
# => ["bc", "abc", "rea", "rui"]
arr.map(&:[].with(/a(.*)/))
# => ["abc", "abc", "at", nil]
arr.map(&:[].with(/a(.*)/, 1))
# => ["bc", "bc", "t", nil]
그리고 inject
두 개의 인수를 블록에 전달하는을 사용하여 작업 할 수도 있습니다 .
%w(abecd ab cd).inject(&:gsub.with('cde'))
# => "cdeeecde"
또는 [속기] 블록 을 속기 블록 으로 전달하는 것과 같은 멋진 기능 :
[['0', '1'], ['2', '3']].map(&:map.with(&:to_i))
# => [[0, 1], [2, 3]]
[%w(a b), %w(c d)].map(&:inject.with(&:+))
# => ["ab", "cd"]
[(1..5), (6..10)].map(&:map.with(&:*.with(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
다음은 @ArupRakshit과 더 자세히 설명하는 대화
입니다. Ruby에서 map (& : method) 구문에 인수를 제공 할 수 있습니까?
As @amcaplan suggested in the comment below, you could create a shorter syntax, if you rename the with
method to call
. In this case, ruby has a built in shortcut for this special method .()
.
So you could use the above like this:
class Symbol
def call(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
a = [1,3,5,7,9]
a.map(&:+.(2))
# => [3, 5, 7, 9, 11]
[(1..5), (6..10)].map(&:map.(&:*.(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
For your example can be done a.map(&2.method(:+))
.
Arup-iMac:$ pry
[1] pry(main)> a = [1,3,5,7,9]
=> [1, 3, 5, 7, 9]
[2] pry(main)> a.map(&2.method(:+))
=> [3, 5, 7, 9, 11]
[3] pry(main)>
Here is how it works :-
[3] pry(main)> 2.method(:+)
=> #<Method: Fixnum#+>
[4] pry(main)> 2.method(:+).to_proc
=> #<Proc:0x000001030cb990 (lambda)>
[5] pry(main)> 2.method(:+).to_proc.call(1)
=> 3
2.method(:+)
gives a Method
object. Then &
, on 2.method(:+)
, actually a call #to_proc
method, which is making it a Proc
object. Then follow What do you call the &: operator in Ruby?.
As the post you linked to confirms, a.map(&:class)
is not a shorthand for a.map {|x| x.class}
but for a.map(&:class.to_proc)
.
This means that to_proc
is called on whatever follows the &
operator.
So you could give it directly a Proc
instead:
a.map(&(Proc.new {|x| x+2}))
I know that most probably this defeats the purpose of your question but I can't see any other way around it - it's not that you specify which method to be called, you just pass it something that responds to to_proc
.
Short answer: No.
Following @rkon's answer, you could also do this:
a = [1,3,5,7,9]
a.map &->(_) { _ + 2 } # => [3, 5, 7, 9, 11]
Instead of patching core classes yourself, as in the accepted answer, it's shorter and cleaner to use the functionality of the Facets gem:
require 'facets'
a = [1,3,5,7,9]
a.map &:+.(2)
There is another native option for enumerables which is pretty only for two arguments in my opinion. the class Enumerable has the method with_object which then returns another Enumerable. So you can call & operator for a method with each item and the object as arguments.
Example:
a = [1,3,5,7,9] a.to_enum.with_object(2).map(&:+) # => [3, 5, 7, 9, 11]
In the case you want more arguments you should repeat the proccess but it's ugly in my opinion:
a = [1,3,5,7,9] a.to_enum.with_object(2).map(&:+).to_enum.with_object(5).map(&:+) # => [8, 10, 12, 14, 16]
I'm not sure about the Symbol#with
already posted, I simplified it quite a bit and it works well:
class Symbol
def with(*args, &block)
lambda { |object| object.public_send(self, *args, &block) }
end
end
(also uses public_send
instead of send
to prevent calling private methods, also caller
is already used by ruby so this was confusing)
'Programming' 카테고리의 다른 글
postgresql 외래 키 구문 (0) | 2020.08.09 |
---|---|
포니 (ORM)는 어떻게 트릭을합니까? (0) | 2020.08.09 |
탐색 용 분리기 (0) | 2020.08.09 |
SQLite에서 "같지 않음"에 대한 구문은 무엇입니까? (0) | 2020.08.09 |
단일 Flask 프로세스가 수신하는 동시 요청 수는 얼마입니까? (0) | 2020.08.09 |