Ruby의 Hash#fetch를 기본값으로 사용하는 이유와 방법
fetch
as an assertion의 에피소드를 보완합니다. 이 에피소드에서는 기본값에 ||
연산자를 사용하는 것과 Hash#fetch
를 사용하는 것의 차이점을 파헤칩니다.감독의 논평: 여기에서 약간의 품질 향상을 볼 수 있습니다. 이 시점에서 나는 내 원래 댓글 색상이 어두운 배경에서 거의 읽을 수 없다는 것을 깨닫고 약간 밝게 했습니다.
그러나 내 음성 해설은 여전히 지루하게 들립니다. 그리고 화면에 새 코드를 입력하는 동안 침묵의 긴 부분에 여전히 만족했습니다. 요즘은 항상 동시 설명과 함께 코딩을 하려고 합니다.
원본 스크립트와 코드를 읽어보세요…
previous episode 에서
#fetch
의 Hash
메서드를 사용하여 주어진 해시 키가 존재한다고 주장하는 방법을 살펴보았습니다.auth = {
'uid' => 12345,
'info' => {
}
}
# ...
email_address = auth['info'].fetch('email')
# ~> -:11:in `fetch': key not found: "email" (KeyError)
# ~> from -:11:in `<main>'
그러나 Hash가 발생시키는
KeyError
가 유용한 오류 메시지에 대한 충분한 컨텍스트를 제공하지 않는다면 어떻게 될까요?가져올 키와 함께
#fetch
메서드는 선택적 블록을 받을 수도 있습니다. 이 블록은 키를 찾을 수 없는 경우에만 평가됩니다.이를 알면 사용자 지정 예외를 발생시키는 블록을
#fetch
에 전달할 수 있습니다.auth['uid'] # => 12345
auth['info'].fetch('email') do
raise "Invalid auth data (missing email)."\
"See https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema"
end
email_address = auth['info'].fetch('email')
# ~> -:10:in `block in <main>': Invalid auth data (missing email).See https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema (RuntimeError)
# ~> from -:8:in `fetch'
# ~> from -:8:in `<main>'
이제 이 코드가 예기치 않게 누락된 키를 만나면 발생한 예외가 문제와 추가 정보를 찾을 수 있는 위치를 모두 설명합니다.
그러나
#fetch
에 대한 블록 인수는 단지 오류를 발생시키기 위한 것이 아닙니다. 예외가 발생하지 않으면 #fetch
는 블록의 결과 값을 호출자에게 반환합니다. 즉, #fetch
는 기본값을 제공하는 데에도 매우 유용합니다. 예를 들어 아무 것도 지정되지 않은 경우 기본 이메일 주소를 제공할 수 있습니다.email_address = auth['info'].fetch('email'){ '[email protected]' }
email_address # => "[email protected]"
이제 기본값으로
#fetch
를 사용하는 것과 기본값으로 ||
operator을 사용하는 것의 차이점이 무엇인지 궁금하실 것입니다. 이들은 처음에는 동일하게 보일 수 있지만 실제로는 미묘하지만 중요하게 다른 방식으로 작동합니다. 차이점을 살펴보겠습니다.다음은 기본값으로
||
연산자를 사용하는 예입니다. 이 코드는 옵션 해시를 수신하고 :logger
키를 사용하여 로거 개체를 찾습니다. 키를 지정하지 않으면 $stdout
에 대한 기본 로거를 생성합니다. 키가 nil
또는 false
인 경우 NullLogger
개체를 대체하여 로깅을 비활성화합니다.비워두면 잘 작동합니다
Hash
.require 'logger'
class NullLogger
def method_missing(*); end
end
options = {}
logger = options[:logger] || Logger.new($stdout)
unless logger
logger = NullLogger.new
end
logger
# => #<Logger:0x000000030545a8
# @default_formatter=
# #<Logger::Formatter:0x00000003054580 @datetime_format=nil>,
# @formatter=nil,
# @level=0,
# @logdev=
# #<Logger::LogDevice:0x00000003054530
# @dev=#<IO:<STDOUT>>,
# @filename=nil,
# @mutex=
# #<Logger::LogDevice::LogDeviceMutex:0x00000003054508
# @mon_count=0,
# @mon_mutex=#<Mutex:0x000000030544b8>,
# @mon_owner=nil>,
# @shift_age=nil,
# @shift_size=nil>,
# @progname=nil>
그러나
false
를 :logger
의 값으로 전달하면 놀라운 결과가 나타납니다.options = {logger: false}
logger = options[:logger] || Logger.new($stdout)
unless logger
logger = NullLogger.new
end
logger
# => #<Logger:0x000000040bb608
# @default_formatter=
# #<Logger::Formatter:0x000000040bb5e0 @datetime_format=nil>,
# @formatter=nil,
# @level=0,
# @logdev=
# #<Logger::LogDevice:0x000000040bb590
# @dev=#<IO:<STDOUT>>,
# @filename=nil,
# @mutex=
# #<Logger::LogDevice::LogDeviceMutex:0x000000040bb568
# @mon_count=0,
# @mon_mutex=#<Mutex:0x000000040bb518>,
# @mon_owner=nil>,
# @shift_age=nil,
# @shift_size=nil>,
# @progname=nil>
그것은 기본 로거가 아니라
NullLogger
이어야 했습니다!여기서 무슨 일이 일어났습니까? 기본값으로
||
와 함께 Hash
를 사용할 때의 문제는 누락된 키와 값이 nil
또는 false
인 키를 구별할 수 없다는 것입니다. 다음은 시연할 코드입니다.{}[:foo] || :default # => :default
{foo: nil}[:foo] || :default # => :default
{foo: false}[:foo] || :default # => :default
대조적으로
#fetch
는 지정된 키가 실제로 누락된 경우에만 기본값에 의지합니다.{}.fetch(:foo){:default} # => :default
{foo: nil}.fetch(:foo){:default} # => nil
{foo: false}.fetch(:foo){:default} # => false
로거 기본 설정 코드에서
#fetch
를 사용하도록 전환하면 의도한 대로 작동합니다.options = {logger: false}
logger = options.fetch(:logger){Logger.new($stdout)}
unless logger
logger = NullLogger.new
end
logger
# => #<NullLogger:0x00000003b73858>
누락된 해시 키에 대한 기본값을 제공하려는 경우 명시적으로 제공된
nil
또는 false
를 누락된 키와 동일하게 처리할지 여부를 신중하게 고려하십시오. 그렇지 않은 경우 #fetch
를 사용하여 기본값을 제공하십시오.오늘은 여기까지입니다. Happy hacking!
Reference
이 문제에 관하여(Ruby의 Hash#fetch를 기본값으로 사용하는 이유와 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/avdi/why-and-how-to-use-ruby-s-hash-fetch-for-default-values-280h텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)