변수가 해시인지 아니면 배열인지를 Ruby에서 확인하는 우아한 방법은 무엇입니까?


140

무엇인지 확인하기 @some_var위해

if @some_var.class.to_s == 'Hash' 

나는 여부를 확인하는 더 우아한 방법이 확신 @some_varA는 Hash나가 Array.


1
Andrew : API를 호출하고 JSON에서 여러 결과가 있으면 배열을 얻지 만 하나만 있으면 단일 요소 배열이 아닌 해시를 얻습니다. 배열 대 해시 검사를 수행하는 것보다 더 나은 방법이 있습니까?
drhyde

2
그래서 당신은 [result_hash, another_result_hash]또는 single_result_hash? 그 API를 만든 사람은 잘하지 못했습니다!
앤드류 그림

2
앤드류, 당신은 맞습니다 . API를 작성한 사람들에게 해시와 배열을 테스트하는 것보다 API를 수정하는 것이 훨씬 쉽습니다.
Olivier 'Ölbaum'Scherler

@drhyde와 같은 상황이 있습니다. 필자의 경우 타사는 HTTParty이며 XML 파일을 구문 분석 한 후 요소에 1-n 개의 자식이있을 수있는 상황을 처리하는 가장 좋은 방법을 결정할 방법이 없습니다.
Dirty Henry

Avdi Grimms 스크린 캐스트 : rubytapas.com/2016/10/17/episode-451-advanced-class-membership을 시청 하고 아마도 카보 가 허용 된 답변에 응답하도록해야합니다.
Alexander Presber

답변:


261

당신은 할 수 있습니다 :

@some_var.class == Hash

또는 다음과 같은 것 :

@some_var.is_a?(Hash)

"is_a?"라는 점은 주목할 가치가 있습니다. 클래스가 객체 조상 트리의 아무 곳에 나 있으면 메소드는 true입니다. 예를 들어 :

@some_var.is_a?(Object)  # => true

@some_var가 Object에서 파생 된 해시 또는 다른 클래스의 인스턴스 인 경우 위의 내용이 적용됩니다. 따라서 == 또는 instance_of?를 사용하여 클래스 유형을 엄격히 일치 시키려면? 방법은 아마도 당신이 찾고있는 것입니다.


20
is_a?true서브 클래스 도 리턴하므로 최상의 옵션 입니다.
Fábio Batista

그리고 물론, 당신은 또한 괄호를 생략, 그래서 @som_var.is_a? Hash작동합니다 :)
Gus Shortz

7
누군가 누군가 ActiveSupport :: HashWithIndifferentAccess의 인스턴스를 전달하면 실제로 문제가 발생할 수 있습니다. 해시처럼 응답하지만 실제로는 해시가 아닙니다. :(
unflores

오리지널 작성자가 타입 검사를하는 루비 방식을 찾고 있었기 때문에 오리 타이핑에 대해 더 많은 답변을 원했습니다.
NoNonesNightmare

3
@unflores ActiveSupport::HashWithIndifferentAccess는 Hash에서 상속 받으므로이 @some_var.is_a?(Hash)경우에도 true를 반환합니다. (방금 같은 질문과 HashWithIndifferentAccess 사례가 있었고 귀하의 의견에서 약간 혼란 스러웠습니다. 그래서 명확히하고 싶습니다)
Stilzk1n

38

우선, 문자 질문에 대한 가장 좋은 대답은

Hash === @some_var

그러나 여기서 오리 타이핑을 수행하는 방법을 보여줌으로써 질문에 실제로 대답해야했습니다. 어떤 오리가 필요한지에 따라 다릅니다.

@some_var.respond_to?(:each_pair)

또는

@some_var.respond_to?(:has_key?)

또는

@some_var.respond_to?(:to_hash)

응용 프로그램에 따라 맞을 수 있습니다.


25

루비에서는 보통 "type"을 찾을 때 실제로 "duck-type"또는 "ducks as duck?"을 원합니다. 특정 방법에 응답하는지 확인할 수 있습니다.

@some_var.respond_to?(:each)

@some_var는 다음에 응답하기 때문에 반복 할 수 있습니다.

실제로 유형을 알고 싶다면 Hash 또는 Array 인 경우 다음을 수행 할 수 있습니다.

["Hash", "Array"].include?(@some_var.class)  #=> check both through instance class
@some_var.kind_of?(Hash)    #=> to check each at once
@some_var.is_a?(Array)   #=> same as kind_of

코드가 데이터 순서에 의존하는 경우 (예 : each_with_index를 사용하는 경우) 작동하지 않습니다. 요소의 순서는 해시와 배열간에 다르게 구현되며 루비 버전마다 다릅니다 ( intertwingly.net/slides/2008/oscon/ruby19/22 )
juan2raid

1
@ juan2raid : 주문이 중요하다면 sort먼저 주문하십시오.
앤드류 그림

@Brandon 두 번째 예는 클래스를 문자열로 변환해야합니다. <br/>["Hash", "Array"].include?(@some_var.class.to_s) #=> check both through instance class
OBCENEIKON

12
Hash === @some_var #=> return Boolean

이것은 case 문과 함께 사용할 수도 있습니다

case @some_var
when Hash
   ...
when Array
   ...
end

4

나는 이것을 사용한다 :

@var.respond_to?(:keys)

해시 및 ActiveSupport :: HashWithIndifferentAccess에서 작동합니다.


4

실제로는 단순한 변수가 아니라 변수가 배열인지 해시인지에 따라 다르게 행동하기를 원할 것입니다. 이 상황에서 우아한 관용구는 다음과 같습니다.

case item
  when Array
   #do something
  when Hash
   #do something else
end

.class메소드를 호출하지 않습니다 item.


2

당신이 사용할 수있는 instance_of?

예 :

@some_var.instance_of?(Hash)

서브 클래스 에서는 작동하지 않습니다 ! 예를 들어 ActiveRecord::Collection및 시도 가 있으면을 instance_of?(Array)반환 false하지만 is_a?(Array)을 반환 true합니다.
Tom Lord

0

객체가 엄격하게 또는 확장인지 테스트 Hash하려면 다음을 사용하십시오.

value = {}
value.is_a?(Hash) || value.is_a?(Array) #=> true

그러나 Ruby의 오리 타이핑을 활용하려면 다음과 같이 할 수 있습니다.

value = {}
value.respond_to?(:[]) #=> true

value[:key]구문을 사용하여 일부 값에만 액세스하려는 경우에 유용 합니다.

유의하시기 바랍니다 Array.new["key"]을 올릴 것이다 TypeError.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.