[ruby] equal ?, eql ?, === 및 ==의 차이점은 무엇입니까?
이 네 가지 방법의 차이점을 이해하려고합니다. 기본적으로 두 피연산자가 모두 동일한 객체를 참조 할 때 true를 반환 ==
하는 메서드 를 호출 한다는 것을 알고 equal?
있습니다.
===
기본적으로도 전화 ==
통화를 equal?
… 좋아,이 모든 세 가지 방법 오버라이드 (override)하지 않는 경우는, 다음 같아요
===
, ==
그리고 equal?
정확히 같은 일을?
이제옵니다 eql?
. 이 작업은 무엇입니까 (기본적으로)? 피연산자의 해시 / ID를 호출합니까?
루비에는 왜 많은 등호가 있습니까? 그것들은 의미론이 달라야합니까?
답변
여기에 Object documentation 이 많이 인용 되어 있습니다. String 과 같은 다른 클래스에서 재정의 되므로이 메소드 와이 메소드에 대한 문서를 읽으십시오 .
참고 사항 : 다른 객체에서 직접 사용하려면 다음과 같이 사용하십시오.
class Object
def all_equals(o)
ops = [:==, :===, :eql?, :equal?]
Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
end
end
"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}
==
— 일반적인 “평등”
객체 수준에서 및 동일한 객체 인
==
경우에만 true를 반환 합니다. 일반적으로이 메서드는 하위 클래스에서 재정의되어 클래스 별 의미를 제공합니다.obj
other
이것은 가장 일반적인 비교이므로 (클래스 작성자로서) 두 객체가 “동일한 지”여부를 결정할 수있는 가장 기본적인 장소입니다.
===
— 대등
Object 클래스의 경우, 호출과 사실상 동일
#==
하지만 일반적으로 후손에 의해 재정의되어 경우 문에 의미가있는 의미를 제공합니다.
이것은 매우 유용합니다. 흥미로운 ===
구현 이있는 것의 예 :
- 범위
- 정규식
- Proc (Ruby 1.9에서)
따라서 다음과 같은 작업을 수행 할 수 있습니다.
case some_object
when /a regex/
# The regex matches
when 2..4
# some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
# the lambda returned true
end
+ 가 코드를 훨씬 깨끗하게 만드는 방법에 대한 깔끔한 예는 여기 내 대답을 참조하십시오 . 물론 자체 구현 을 제공하여 사용자 정의 의미를 얻을 수 있습니다 .case
Regex
===
case
eql?
— Hash
평등
eql?
경우 메소드는 true를 돌려줍니다obj
과other
동일한 해시 키를 참조하십시오. 이는Hash
구성원의 동등성을 테스트 하는 데 사용됩니다 . 클래스의 객체를 들어Object
,eql?
동의어입니다==
. 서브 클래스는 일반적으로eql?
재정의 된==
메소드 에 별명 을 지정하여 이러한 전통을 이어가지 만 예외가 있습니다.Numeric
예를 들어 유형은에 대해 유형 변환을 수행==
하지만에 대해서는 수행 하지 않습니다eql?
.1 == 1.0 #=> true 1.eql? 1.0 #=> false
따라서 자신의 용도에 따라 이것을 재정의하거나 두 방법이 동일한 방식으로 작동하도록 재정의 ==
하고 사용할 수 있습니다 alias :eql? :==
.
equal?
— 정체성 비교
와 달리
==
,equal?
메소드는 서브 클래스에 의해 재정의되어서는 안됩니다. 즉, 객체 아이덴티티를 결정하는 데 사용됩니다 (즉,a.equal?(b)
iff는와a
같은 객체입니다b
).
이것은 효과적으로 포인터 비교입니다.
답변
나는 jtbandes 답변을 좋아하지만 꽤 길기 때문에 내 자신의 간단한 답변을 추가 할 것입니다.
==
, ===
, eql?
,equal?
4 비교기, 즉이다. Ruby에서 두 객체를 비교하는 4 가지 방법
Ruby에서 모든 비교기 (및 대부분의 연산자)는 실제로 메소드 호출이므로 이러한 비교 메소드의 의미를 직접 변경, 덮어 쓰기 및 정의 할 수 있습니다. 그러나 Ruby의 내부 언어 구조가 어떤 비교자를 사용하는지 이해하는 것이 중요합니다.
==
(값 비교)
루비는 : ==를 사용하여 두 객체 의 값 을 비교합니다 . 해시 값 :
{a: 'z'} == {a: 'Z'} # => false
{a: 1} == {a: 1.0} # => true
===
(케이스 비교)
루비는 경우 / 구문에서 : ===를 사용합니다. 다음 코드 스 니펫은 논리적으로 동일합니다.
case foo
when bar; p 'do something'
end
if bar === foo
p 'do something'
end
eql?
(해시 키 비교)
Ruby는 : eql을 사용합니다. (해시 메소드와 함께) 해시 키를 비교합니다. 대부분의 수업에서 : eql? : ==와 동일합니다.
: eql에 대한 지식? 자신 만의 특수 클래스를 만들려는 경우에만 중요합니다.
class Equ
attr_accessor :val
alias_method :initialize, :val=
def hash() self.val % 2 end
def eql?(other) self.hash == other.hash end
end
h = {Equ.new(3) => 3, Equ.new(8) => 8, Equ.new(15) => 15} #3 entries, but 2 are :eql?
h.size # => 2
h[Equ.new(27)] # => 15
참고 : 일반적으로 사용되는 Ruby 클래스 세트는 Hash-key-comparison에 의존합니다.
equal?
(개체 식별 비교)
루비 용도 : 동일? 두 객체가 동일한 지 확인합니다. BasicObject 클래스의이 메소드는 겹쳐 써서는 안됩니다.
obj = obj2 = 'a'
obj.equal? obj2 # => true
obj.equal? obj.dup # => false
답변
같음 연산자 : == 및! =
등호 또는 이중 등호라고도하는 == 연산자는 두 객체가 모두 같으면 true를 반환하고 그렇지 않으면 false를 반환합니다.
"koan" == "koan" # Output: => true
부등식이라고도하는! = 연산자는 ==의 반대입니다. 두 객체가 같지 않으면 true를 반환하고 같으면 false를 반환합니다.
"koan" != "discursive thought" # Output: => true
동일한 순서로 요소가 동일한 두 배열이 같지 않고 같은 문자의 대문자 및 소문자 버전이 같지 않습니다.
다른 유형 (예 : 정수 및 부동 소수점)의 숫자를 비교할 때 숫자 값이 같으면 ==가 true를 반환합니다.
2 == 2.0 # Output: => true
같은?
두 피연산자가 같은지 테스트하는 == 연산자와 달리 equal 메서드는 두 피연산자가 동일한 객체를 참조하는지 확인합니다. 이것은 루비에서 가장 엄격한 평등 형태입니다.
예 : a = “zen”b = “zen”
a.object_id # Output: => 20139460
b.object_id # Output :=> 19972120
a.equal? b # Output: => false
위의 예에서 값이 같은 두 개의 문자열이 있습니다. 그러나 이들은 서로 다른 객체 ID를 가진 두 개의 별개의 객체입니다. 따라서 동등합니까? 메소드는 false를 리턴합니다.
다시 시도하겠습니다. 이번에는 b 만 a에 대한 참조입니다. 객체 ID는 동일한 객체를 가리 키기 때문에 두 변수에 대해 동일합니다.
a = "zen"
b = a
a.object_id # Output: => 18637360
b.object_id # Output: => 18637360
a.equal? b # Output: => true
eql?
해시 클래스에서 eql? 이 방법은 키가 동일한 지 테스트하는 데 사용됩니다. 이것을 설명하기 위해서는 약간의 배경이 필요합니다. 컴퓨팅의 일반적인 맥락에서, 해시 함수는 임의의 크기의 문자열 (또는 파일)을 취하여 일반적으로 해시라고하는 해시 코드라고하는 고정 크기의 문자열 또는 정수를 생성합니다. 일반적으로 사용되는 일부 해시 코드 유형은 MD5, SHA-1 및 CRC입니다. 이들은 암호화 알고리즘, 데이터베이스 색인 작성, 파일 무결성 검사 등에 사용됩니다. Ruby와 같은 일부 프로그래밍 언어는 해시 테이블이라는 콜렉션 유형을 제공합니다. 해시 테이블은 고유 키와 해당 값으로 구성된 쌍으로 데이터를 저장하는 사전과 유사한 콜렉션입니다. 후드 아래에서 해당 키는 해시 코드로 저장됩니다. 해시 테이블은 일반적으로 해시라고합니다. hash라는 단어가 해시 코드 또는 해시 테이블을 나타내는 방법에 주목하십시오.
Ruby는 해시 코드 생성을위한 해시라는 내장 메소드를 제공합니다. 아래 예제에서 문자열을 가져와 해시 코드를 반환합니다. 동일한 값을 가진 문자열이 다른 객체 ID를 가진 별개의 객체 임에도 불구하고 항상 동일한 해시 코드를 갖는 방법에 주목하십시오.
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
해시 메소드는 모든 Ruby 객체의 기본 루트 인 Object 클래스에 포함 된 커널 모듈에서 구현됩니다. Symbol 및 Integer와 같은 일부 클래스는 기본 구현을 사용하고 String 및 Hash와 같은 일부 클래스는 자체 구현을 제공합니다.
Symbol.instance_method(:hash).owner # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel
String.instance_method(:hash).owner # Output: => String
Hash.instance_method(:hash).owner # Output: => Hash
Ruby에서 해시 (컬렉션)에 무언가를 저장하면 키 (예 : 문자열 또는 기호)로 제공된 객체가 해시 코드로 변환되어 저장됩니다. 나중에 해시 (컬렉션)에서 요소를 검색 할 때 해시 코드로 변환되어 기존 키와 비교되는 키로 객체를 제공합니다. 일치하는 항목이 있으면 해당 항목의 값이 반환됩니다. 비교는 eql? 후드 아래의 방법.
"zen".eql? "zen" # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true
대부분의 경우 eql? 메소드는 == 메소드와 유사하게 작동합니다. 그러나 몇 가지 예외가 있습니다. 예를 들어 eql? 정수를 부동 소수점과 비교할 때 암시 적 유형 변환을 수행하지 않습니다.
2 == 2.0 # Output: => true
2.eql? 2.0 # Output: => false
2.hash == 2.0.hash # Output: => false
대소 문자 평등 연산자 : ===
String, Range 및 Regexp와 같은 Ruby의 내장 클래스는 대소 문자 구분, 트리플 같음 또는 삼등이라고도하는 === 연산자의 자체 구현을 제공합니다. 각 클래스에서 다르게 구현되므로 호출 한 객체의 유형에 따라 다르게 동작합니다. 일반적으로 오른쪽에있는 개체가 왼쪽에있는 개체의 “포함”또는 “구성원”이면 true를 반환합니다. 예를 들어, 객체가 클래스 (또는 그 서브 클래스 중 하나)의 인스턴스인지 테스트하는 데 사용할 수 있습니다.
String === "zen" # Output: => true
Range === (1..2) # Output: => true
Array === [1,2,3] # Output: => true
Integer === 2 # Output: => true
작업에 가장 적합한 다른 방법으로도 동일한 결과를 얻을 수 있습니다. 효율성과 간결성을 유지하면서 가능한 한 명시 적으로 작성하여 읽기 쉬운 코드를 작성하는 것이 좋습니다.
2.is_a? Integer # Output: => true
2.kind_of? Integer # Output: => true
2.instance_of? Integer # Output: => false
2와 같은 정수는 Integer 클래스의 서브 클래스 인 Fixnum 클래스의 인스턴스이므로 마지막 예제는 false를 리턴했습니다. ===, is_a? 그리고 instance_of? 객체가 주어진 클래스 또는 서브 클래스의 인스턴스 인 경우 메소드는 true를 리턴합니다. instance_of 메소드는 엄격하며 오브젝트가 서브 클래스가 아닌 정확한 클래스의 인스턴스 인 경우에만 true를 리턴합니다.
is_a? 그리고 kind_of? 메소드는 Kernel 모듈에서 구현되며 Object 클래스에 혼합되어 있습니다. 둘 다 같은 방법에 대한 별칭입니다. 확인하자 :
Kernel.instance_method (: kind_of?) == Kernel.instance_method (: is_a?) # 출력 : => true
===의 범위 구현
범위 객체에서 === 연산자를 호출하면 오른쪽의 값이 왼쪽의 범위 내에 있으면 true를 반환합니다.
(1..4) === 3 # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6 # Output: => false
("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false
=== 연산자는 왼쪽 개체의 === 메서드를 호출합니다. 따라서 (1..4) === 3은 (1..4). === 3과 같습니다. 즉, 왼쪽 피연산자의 클래스는 === 메소드의 구현을 정의합니다. 피연산자 위치는 서로 호환되지 않습니다.
=== 정규 표현식 구현
오른쪽의 문자열이 왼쪽의 정규식과 일치하면 true를 반환합니다. / zen / === “오늘 연습 zazen”# 출력 : => true # “오늘 연습 zazen”과 같습니다 == / zen /
case / w 문에서 === 연산자의 내재적 사용법
이 연산자는 대 / 소문자를 명시 할 때도 사용됩니다. 그것이 가장 일반적으로 사용됩니다.
minutes = 15
case minutes
when 10..20
puts "match"
else
puts "no match"
end
# Output: match
위의 예에서 Ruby가 암시 적으로 double equal operator (==)를 사용한 경우 10..20 범위는 15와 같은 정수와 같지 않습니다. triple equal operator (===)는 모든 경우 / 언제든지 진술에 암시 적으로 사용됩니다. 위 예제의 코드는 다음과 같습니다.
if (10..20) === minutes
puts "match"
else
puts "no match"
end
패턴 일치 연산자 : = ~ 및! ~
= ~ (등호) 및! ~ (bang-tilde) 연산자는 문자열과 기호를 정규식 패턴과 일치시키는 데 사용됩니다.
String 및 Symbol 클래스에서 = ~ 메서드를 구현하려면 정규식 (Regexp 클래스의 인스턴스)이 인수로 필요합니다.
"practice zazen" =~ /zen/ # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil
:zazen =~ /zen/ # Output: => 2
:zazen =~ /discursive thought/ # Output: => nil
Regexp 클래스의 구현에는 문자열 또는 기호가 인수로 필요합니다.
/zen/ =~ "practice zazen" # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil
모든 구현에서 문자열 또는 기호가 Regexp 패턴과 일치하면 일치하는 위치 (인덱스) 인 정수를 반환합니다. 일치하는 것이 없으면 nil을 반환합니다. Ruby에서 정수 값은 “truthy”이고 nil은 “falsy”이므로 = ~ 연산자는 if 문과 삼항 연산자에 사용될 수 있습니다.
puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes
패턴 일치 연산자는 또한 짧은 if 문을 작성하는 데 유용합니다. 예:
if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
true
end
! ~ 연산자는 = ~의 반대입니다. 일치하는 것이 없으면 true를, 일치하는 경우 false를 반환합니다.
자세한 내용은 이 블로그 게시물 에서 확인할 수 있습니다 .
답변
루비는 평등을 처리하기위한 여러 가지 방법을 노출합니다
a.equal?(b) # object identity - a and b refer to the same object
a.eql?(b) # object equivalence - a and b have the same value
a == b # object equivalence - a and b have the same value with type conversion.
아래 링크를 클릭하여 계속 읽으면 요약 된 내용이 명확하게 나옵니다.
https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers
그것이 다른 사람들을 돕기를 바랍니다.
답변
=== #-대소 문자 평등
== # — 일반 평등
둘 다 비슷하게 작동하지만 “===”경우에도 진술을 수행
"test" == "test" #=> true
"test" === "test" #=> true
여기 차이점
String === "test" #=> true
String == "test" #=> false
답변
===
연산자 를 확장하고 싶습니다 .
===
평등 연산자가 아닙니다!
아니.
그 요점을 실제로 살펴 보겠습니다.
===
Javascript와 PHP에서 동등 연산자로 익숙 할 수도 있지만 Ruby에서는 동등 연산자가 아니며 기본적으로 의미가 다릅니다.
그래서 무엇을 ===
합니까?
===
패턴 매칭 연산자입니다!
===
정규식과 일치===
범위 구성원 확인===
클래스의 인스턴스인지 확인===
람다 식 호출===
때로는 평등을 확인하지만 대부분 그렇지 않습니다
이 광기는 어떻게 이해가 되나요?
Enumerable#grep
===
내부적으로 사용case when
진술은===
내부적으로 사용- 재미있는 사실, 내부적으로
rescue
사용===
그렇기 때문에 case when
명령문 에서 정규식, 클래스 및 범위, 람다 식을 사용할 수 있습니다 .
몇 가지 예
case value
when /regexp/
# value matches this regexp
when 4..10
# value is in range
when MyClass
# value is an instance of class
when ->(value) { ... }
# lambda expression returns true
when a, b, c, d
# value matches one of a through d with `===`
when *array
# value matches an element in array with `===`
when x
# values is equal to x unless x is one of the above
end
이 모든 예제 pattern === value
는 grep
방법 뿐만 아니라 작동 합니다.
arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)
# => ["quick", "fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the", "quick", "brown", "fox"]
arr.grep(1)
# => [1, 1]
답변
위의 모든 것에 대한 간단한 테스트를 작성했습니다.
def eq(a, b)
puts "#{[a, '==', b]} : #{a == b}"
puts "#{[a, '===', b]} : #{a === b}"
puts "#{[a, '.eql?', b]} : #{a.eql?(b)}"
puts "#{[a, '.equal?', b]} : #{a.equal?(b)}"
end
eq("all", "all")
eq(:all, :all)
eq(Object.new, Object.new)
eq(3, 3)
eq(1, 1.0)