일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Java
- Convariance
- 공짜블로그
- Test
- Mutation testing
- standard input
- IntelliJ
- JPA
- kotlin
- 코틀린 노트북
- resizer 구현
- 의존성역전원칙
- 코틀린
- hugo 로 블로그
- ruby
- resize image with go
- InnoDB
- 코틀린 in
- change refresh rate
- image resizer with go
- cli 만들기
- 코틀린 out
- output stream
- MySQL
- Pitest
- 돌연변이 테스팅
- 개인블로그 hugo
- standard output
- 객체지향
- 자바
- Today
- Total
Rlog
Ruby Block, Proc, Lambda 본문
Block?
Ruby 에는 Block method 라는 것이 존재한다. 다른 언어로 치면 익명함수와 비슷한 존재이다.
함수의 몸체 그 자체이다.
Block 메소드에 넘겨줘야 할 Argument 는 Pipe(|) 로 적어주고 실행될 몸체는 아래와 같이 적어준다.
[1, 2, 3].each { |num| puts num }
yield?
루비에는 yield method 가 있는데 이는 block method 를 호출하는 코드이다. 아래의 예시를 보자.
def hello_block?
yield
end
hello_block? { puts "Hello Block!" }
& expression
특히 Ruby 에서는 &
을 쓸때 block 을 넘겨주어야 한다. 아래의 예시를 보자.
def hello_empresand?(&block)
block.call
end
hello_empresand? {puts "Hello empersand!"}
우리가 block 을 객체처럼 들고 있으려면 어떻게 해야할까. 예를 들면 아래와 같이 말이다.
block_var = { puts "Hello empersand!" }
main.rb:13: syntax error, unexpected '}', expecting end-of-input
위와 같은 방법으로 들고 있기 위해서 주로 Proc 혹은 lambda 를 이용한다.
하지만 Lambda 와 Proc 을 이용하면 &를 이용할 수 없다. 아래와 같은 상황을 보자.
block_var = -> { puts "Hello empersand!" }
block_proc_var = Proc.new { puts "Hello empersand!" }
hello_empresand? block_var
hello_empresand? block_proc_var
main.rb:9:in `hello_empresand?': wrong number of arguments (given 1, expected 0) (ArgumentError)
from main.rb:15:in `<main>'
위와 같이 오류가 난다. 왜 이럴까 &
는 어떤 역할을 하길래 이런 일이 일어나는 걸까?
사실 Block만 &
로 받아서 이용할 수 있는 이유는 &
가 Block 을 Proc 객체로 치환해주기 때문이다.
아래의 메소드를 한번보자
def hello_empresand?(&block)
puts block
end
hello_empresand? { puts "Hello empersand!" }
hello_empresand? &Proc.new { puts "Hello empersand!" }
#<Proc:0x00007fe49397d1a8 main.rb:22>
#<Proc:0x00007fe49397cfa0 main.rb:23>
위와 같이 Block 이 Proc 으로 치환된걸 확인할 수 있다.
따라서 해당 메소드를 변경해보자
def hello_emp(block)
block.call
end
block_var = -> { puts "Hello empersand!" }
block_proc_var = Proc.new { puts "Hello ampersand!" }
hello_emp block_var
hello_emp block_proc_var
Hello empersand!
Hello empersand!
위와 같이 잘 실행되는 걸 볼 수 있다.
lambda vs proc
둘다 사용방법은 아래와 같이 비슷하다.
block_var = -> { puts "Hello empersand!" }
block_proc_var = Proc.new { puts "Hello empersand!" }
그렇다면 두객체는 어떻게 비교할까? 아래와 같은 방법으로 비교 가능하다.
Proc.new{}.lambda? # => false
proc{}.lambda? # => false
lambda{}.lambda? # => true
->{}.lambda? # => true
하지만 위와 같은 이유만으로는 왜 Proc 과 lambda 가 따로 있는지를 알기 힘드므로 결정적인 차이를 알아야 한다.
결정적인 차이는 return 을 하는 방식의 차이이다.
def return_diff(num)
puts num.call + 1
end
proc_var = Proc.new {return 1}
lambda_var = -> {return 1}
return_diff lambda_var
return_diff proc_var
#result
2
위와 같이 똑같이 생각하지만, lamdba_var 로 실행한 결과만 결과값이 출력된다. 왜 일까?
이건 개념적 차이가 있는데 lambda 라는 것은 결국에 어떤 걸 받아서 평가해 내는 평가 함수가 되는데, Proc 은 하나의 Process 를 명시한 Block 처럼 여겨지므로 return 을 하지않는다.
따라서 return 을 할 블록이여야 한다면 lambda 를 쓰는 것이 맞다.