迅速に、2つの等価演算子があるようです:二重の等号(==
)と三重の等価(===
)、2つの違いは何ですか?
迅速に、2つの等価演算子があるようです:二重の等号(==
)と三重の等価(===
)、2つの違いは何ですか?
回答:
要するに:
==
演算子は、それらのインスタンス値が等しいかどうかをチェックし、 "equal to"
===
演算子は、参照が同じインスタンスを指しているかどうかをチェックし、 "identical to"
長い答え:
クラスは参照型であり、複数の定数と変数が背後でクラスの同じ単一のインスタンスを参照することが可能です。クラス参照はランタイムスタック(RTS)に残り、それらのインスタンスはメモリのヒープ領域に残ります。平等を制御する==
とは、それらのインスタンスが互いに等しいかどうかを意味します。等しくなるために同じインスタンスである必要はありません。このためには、カスタムクラスに同等基準を提供する必要があります。デフォルトでは、カスタムクラスと構造は、「等しい」演算子==
および「等しくない」演算子と呼ばれる、等価演算子のデフォルト実装を受け取りません!=
。これを行うには、カスタムクラスがEquatable
プロトコルとそのstatic func == (lhs:, rhs:) -> Bool
機能に準拠する必要があります
例を見てみましょう:
class Person : Equatable {
let ssn: Int
let name: String
init(ssn: Int, name: String) {
self.ssn = ssn
self.name = name
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.ssn == rhs.ssn
}
}
P.S.:
ssn(社会保障番号)は一意の番号であるため、それらの名前が等しいかどうかを比較する必要はありません。
let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")
if person1 == person2 {
print("the two instances are equal!")
}
person1およびperson2参照はヒープ領域内の2つの異なるインスタンスをポイントしますが、それらのインスタンスは、ssn番号が等しいため等しいです。したがって、出力はthe two instance are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===
演算子は、参照が同じインスタンスを指しているかどうかをチェックします"identical to"
。person1とperson2はヒープ領域に2つの異なるインスタンスを持っているので、それらは同一ではなく、出力はthe two instance are not identical!
let person3 = person1
P.S:
クラスは参照型であり、person1の参照はこの割り当て操作でperson3にコピーされるため、両方の参照がヒープ領域の同じインスタンスを指します。
if person3 === person1 {
print("the two instances are identical!")
}
それらは同一であり、出力は the two instances are identical!
!==
および===
はアイデンティティー演算子であり、2つのオブジェクトが同じ参照を持っているかどうかを判別するために使用されます。
Swiftには2つのID演算子(===および!==)も用意されています。これを使用して、2つのオブジェクト参照が両方とも同じオブジェクトインスタンスを参照しているかどうかをテストします。
抜粋:Apple Inc.「The Swift Programming Language」iBooks。https://itun.es/us/jEUH0.l
var
またはlet
)が一意のコピーであることです。つまり、ポインターを作成した値は、最初に作成した値とは異なるため、ポインターを作成しても意味がありません。もう1つは、Swiftの値のセマンティクスの定義がストレージを抽象化することです。コンパイラーは、使用する行(レジスター、命令のエンコードなど)を超えてアクセス可能なメモリー位置に値を格納することなく、最適化することができます。
両方のObjective-Cとスウィフトで、==
および!=
数値の値の等価性演算子試験(例えば、NSInteger
、NSUInteger
、int
、Objective-CのとでInt
、UInt
等スイフトで)。オブジェクト(Objective-CのNSObject / NSNumberとサブクラス、==
およびSwiftの参照型)の場合!=
、オブジェクト/参照型が同じもの(つまり、同じハッシュ値)であるか、それぞれ同じでないことをテストします。 。
let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true
SwiftのID等価演算子、===
および!==
、参照等価をチェックします。したがって、おそらく参照等価演算子IMO と呼ばれるはずです。
a === b // false
a === c // true
Swiftのカスタム参照型(Equatableに準拠するクラスをサブクラス化しないもの)は自動的に等号演算子を実装しませんが、同一性演算子は引き続き適用されることも指摘する価値があります。また、を実装すると==
、!=
自動的に実装されます。
class MyClass: Equatable {
let myProperty: String
init(s: String) {
myProperty = s
}
}
func ==(lhs: MyClass, rhs: MyClass) -> Bool {
return lhs.myProperty == rhs.myProperty
}
let myClass1 = MyClass(s: "Hello")
let myClass2 = MyClass(s: "Hello")
myClass1 == myClass2 // true
myClass1 != myClass2 // false
myClass1 === myClass2 // false
myClass1 !== myClass2 // true
これらの等値演算子は、どちらの言語の構造体などの他の型にも実装されていません。ただし、カスタムオペレーターはSwiftで作成できます。これにより、例えば、オペレーターを作成してCGPointの同等性をチェックできます。
infix operator <==> { precedence 130 }
func <==> (lhs: CGPoint, rhs: CGPoint) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
let point1 = CGPoint(x: 1.0, y: 1.0)
let point2 = CGPoint(x: 1.0, y: 1.0)
point1 <==> point2 // true
==
NSNumber
Objective-Cの同等性をテストしません。NSNumber
でNSObject
、それはアイデンティティのためにテストするようにします。SOMETIMESが機能する理由は、タグ付きポインター/キャッシュされたオブジェクトリテラルが原因です。非リテラルと比較すると、十分な数の32ビットデバイスでは失敗します。
===
(または!==
)==
オブジェクト- C(ポインタ等価)です。==
(または!=
)isEqual:
Obj-C動作のデフォルトのように。ここで3つのインスタンスを比較します (クラスは参照型です)
class Person {}
let person = Person()
let person2 = person
let person3 = Person()
person === person2 // true
person === person3 // false
isEqual:
スウィフトに:override func isEqual(_ object: Any?) -> Bool {}
Swifts ===
には、単なるポインタ演算を超える微妙な点があります。Objective-Cでは、2つのポインター(つまりNSObject *
)を比較することができました==
が、コンパイル時に型がより大きな役割を果たすため、Swift ではこれは当てはまりません。
遊び場はあなたを与えるでしょう
1 === 2 // false
1 === 1 // true
let one = 1 // 1
1 === one // compile error: Type 'Int' does not conform to protocol 'AnyObject'
1 === (one as AnyObject) // true (surprisingly (to me at least))
文字列では、これに慣れる必要があります。
var st = "123" // "123"
var ns = (st as NSString) // "123"
st == ns // true, content equality
st === ns // compile error
ns === (st as NSString) // false, new struct
ns === (st as AnyObject) // false, new struct
(st as NSString) === (st as NSString) // false, new structs, bridging is not "free" (as in "lunch")
NSString(string:st) === NSString(string:st) // false, new structs
var st1 = NSString(string:st) // "123"
var st2 = st1 // "123"
st1 === st2 // true
var st3 = (st as NSString) // "123"
st1 === st3 // false
(st as AnyObject) === (st as AnyObject) // false
しかし、次のように楽しむこともできます。
var st4 = st // "123"
st4 == st // true
st4 += "5" // "1235"
st4 == st // false, not quite a reference, copy on write semantics
私はあなたがもっともっと面白いケースを考えることができると確信しています:-)
Swift 3の更新(JakubTruhlářからのコメントで提案)
1===2 // Compiler error: binary operator '===' cannot be applied to two 'Int' operands
(1 as AnyObject) === (2 as AnyObject) // false
let two = 2
(2 as AnyObject) === (two as AnyObject) // false (rather unpleasant)
(2 as AnyObject) === (2 as AnyObject) // false (this makes it clear that there are new objects being generated)
これはと少し整合性がありますがType 'Int' does not conform to protocol 'AnyObject'
、次のようになります。
type(of:(1 as AnyObject)) // _SwiftTypePreservingNSNumber.Type
しかし、明示的な変換により、何かが起こっている可能性があることが明らかになります。文字列側ではNSString
、私たちがimport Cocoa
いる限り引き続き利用できます。次に、
var st = "123" // "123"
var ns = (st as NSString) // "123"
st == ns // Compile error with Fixit: 'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?
st == ns as String // true, content equality
st === ns // compile error: binary operator '===' cannot be applied to operands of type 'String' and 'NSString'
ns === (st as NSString) // false, new struct
ns === (st as AnyObject) // false, new struct
(st as NSString) === (st as NSString) // false, new structs, bridging is not "free" (as in "lunch")
NSString(string:st) === NSString(string:st) // false, new objects
var st1 = NSString(string:st) // "123"
var st2 = st1 // "123"
st1 === st2 // true
var st3 = (st as NSString) // "123"
st1 === st3 // false
(st as AnyObject) === (st as AnyObject) // false
2つのStringクラスを持つことはまだ混乱していますが、暗黙の変換を削除すると、おそらく少しわかりやすくなります。
===
演算子を使用して比較することはできませんInts
。Swift 3にはありません
===
構造体は値型であるため、意味がありません。特に、覚えておかなければならない3つのタイプがあります。1や "foo"などのリテラルタイプは変数にバインドされておらず、通常は実行時に処理しないため、通常はコンパイルにのみ影響します。構造体のようなタイプInt
とString
あなたが変数にリテラルを割り当てるときに何を得るである、とのようなクラスAnyObject
とNSString
。
たとえば、クラスの2つのインスタンスを作成するとします。例myClass
:
var inst1 = myClass()
var inst2 = myClass()
それらのインスタンスを比較できます
if inst1 === inst2
引用:
2つのオブジェクト参照が両方とも同じオブジェクトインスタンスを参照しているかどうかをテストするために使用します。
抜粋:Apple Inc.「The Swift Programming Language」iBooks。https://itun.es/sk/jEUH0.l
Any
オブジェクトに関連するわずかな貢献。
私はの周りでユニットテストを扱っていましたNotificationCenter
。これはAny
、同等性を比較したいパラメーターとして使用します。
ただし、Any
等価演算では使用できないため、変更する必要がありました。最終的に、私は次のアプローチで解決しました。これにより、特定の状況で平等を得ることができました。ここでは、単純化した例を示します。
func compareTwoAny(a: Any, b: Any) -> Bool {
return ObjectIdentifier(a as AnyObject) == ObjectIdentifier(b as AnyObject)
}
この関数は、オブジェクトに一意のアドレスを提供するObjectIdentifierを利用して、テストできるようにします。
ObjectIdentifier
上記のリンクでアップルごとに注意すべき1つの項目:
Swiftでは、クラスインスタンスとメタタイプのみが一意のIDを持っています。構造体、列挙型、関数、またはタプルのアイデンティティの概念はありません。
==
2つの変数が等しいかどうかを確認するために使用されます
2 == 2
。しかし、===
それが同等の場合、つまり、クラスの場合に2つのインスタンスが同じオブジェクトの例を参照する場合、他の多くのインスタンスが保持する参照が作成されます。
Swift 4:===でのみ機能する単体テストの別の例
注:以下のテストは==で失敗し、===で機能します
func test_inputTextFields_Delegate_is_ViewControllerUnderTest() {
//instantiate viewControllerUnderTest from Main storyboard
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewControllerUnderTest = storyboard.instantiateViewController(withIdentifier: "StoryBoardIdentifier") as! ViewControllerUnderTest
let _ = viewControllerUnderTest.view
XCTAssertTrue(viewControllerUnderTest.inputTextField.delegate === viewControllerUnderTest)
}
そしてクラスは
class ViewControllerUnderTest: UIViewController, UITextFieldDelegate {
@IBOutlet weak var inputTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
inputTextField.delegate = self
}
}
==を使用した場合の単体テストのエラーは、 Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'
==
isisEqual:
、またはクラスで定義されたセマンティック同値から来ています。===
Swiftは==
(Obj)C —ポインタの等価性、またはオブジェクトIDにあります。