อย่างรวดเร็วดูเหมือนว่าจะมีผู้ประกอบการสองรายที่เท่าเทียมกัน: double equals ( ==
) และ triple เท่ากับ ( ===
) อะไรคือความแตกต่างระหว่างทั้งสอง?
อย่างรวดเร็วดูเหมือนว่าจะมีผู้ประกอบการสองรายที่เท่าเทียมกัน: double equals ( ==
) และ triple เท่ากับ ( ===
) อะไรคือความแตกต่างระหว่างทั้งสอง?
คำตอบ:
ในระยะสั้น:
==
ผู้ประกอบการตรวจสอบว่าค่าอินสแตนซ์ของพวกเขาจะเท่ากัน "equal to"
===
ผู้ประกอบการตรวจสอบว่าการอ้างอิงชี้ไปที่อินสแตนซ์เดียวกัน "identical to"
คำตอบยาว:
คลาสเป็นชนิดของการอ้างอิงมันเป็นไปได้ที่ค่าคงที่และตัวแปรหลายตัวสามารถอ้างถึงอินสแตนซ์เดียวของชั้นเรียนที่อยู่เบื้องหลัง การอ้างอิงคลาสอยู่ใน Run Time Stack (RTS) และอินสแตนซ์ของมันยังคงอยู่ในพื้นที่ Heap ของหน่วยความจำ เมื่อคุณควบคุมความเท่าเทียมกันกับ==
มันหมายความว่าถ้าอินสแตนซ์ของพวกเขาจะเท่ากัน ไม่จำเป็นต้องเป็นอินสแตนซ์เดียวกันเพื่อให้เท่ากัน สำหรับสิ่งนี้คุณต้องให้เกณฑ์ความเท่าเทียมกับคลาสที่คุณกำหนดเอง โดยค่าเริ่มต้นเรียนที่กำหนดเองและโครงสร้างไม่ได้รับการเริ่มต้นใช้งานของผู้ประกอบการที่สมดุลที่รู้จักในฐานะ“เท่ากับ” ผู้ประกอบการ==
และ“ไม่เท่ากับ” !=
ผู้ประกอบการ ในการทำเช่นนี้คลาสที่กำหนดเองของคุณต้องเป็นไปตาม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 การอ้างอิงชี้สองอินสแตนซ์ที่แตกต่างกันในพื้นที่ฮีปอินสแตนซ์ของพวกเขาจะเท่ากันเนื่องจากหมายเลข 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 มีอินสแตนซ์ที่แตกต่างกันสองรายการในพื้นที่ฮีปจึงไม่เหมือนกันและมีเอาต์พุต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!
!==
และ===
เป็นตัวดำเนินการเอกลักษณ์และใช้เพื่อตรวจสอบว่าวัตถุสองรายการมีการอ้างอิงเดียวกันหรือไม่
Swift ยังมีตัวดำเนินการเอกลักษณ์สองตัว (=== และ! ==) ซึ่งคุณใช้เพื่อทดสอบว่าวัตถุสองรายการอ้างอิงทั้งสองอ้างถึงอินสแตนซ์วัตถุเดียวกันหรือไม่
ข้อความที่ตัดตอนมาจาก: Apple Inc. “ ภาษาการเขียนโปรแกรม Swift” iBooks https://itun.es/us/jEUH0.l
var
หรือlet
) ของค่าเป็นสำเนาที่ไม่ซ้ำกันดังนั้นจึงไม่มีความหมายในการสร้างพอยน์เตอร์เนื่องจากค่าที่คุณทำตัวชี้ไปยังเป็นค่าที่แตกต่างจากที่คุณสร้างขึ้นครั้งแรก อีกประการหนึ่งคือคำจำกัดความของค่าความหมายของสวิฟท์ย่อมาจากหน่วยความจำ - คอมไพเลอร์มีอิสระในการเพิ่มประสิทธิภาพสูงสุดและรวมถึงไม่เก็บค่าของคุณในตำแหน่งหน่วยความจำที่เข้าถึงได้เกินกว่าบรรทัดที่ใช้
ในทั้งสอง Objective-C และสวิฟท์ที่==
และ!=
การทดสอบผู้ประกอบการเพื่อความเท่าเทียมกันค่าสำหรับค่าตัวเลข (เช่นNSInteger
, NSUInteger
, int
ใน Objective-C และInt
, UInt
ฯลฯ ในสวิฟท์) สำหรับวัตถุ (NSObject / NSNumber และ subclasses ใน Objective-C และประเภทการอ้างอิงใน Swift) ==
และ!=
ทดสอบว่าวัตถุ / ประเภทการอ้างอิงเป็นสิ่งเดียวกันเหมือนกัน - เช่นค่าแฮชเดียวกัน - หรือไม่เหมือนกันตามลำดับ .
let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true
สวิฟท์ตัวตนของความเท่าเทียมกันผู้ประกอบการ===
และ!==
ตรวจสอบความเสมอภาคอ้างอิง - จึงควรอาจจะเรียกว่าความเสมอภาคอ้างอิงประกอบการ 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- บิตเมื่อเปรียบเทียบตัวอักษรที่ไม่ใช่
===
(หรือ!==
)==
ใน Obj-C (ความเท่าเทียมกันของตัวชี้)==
(หรือ!=
)isEqual:
ในพฤติกรรม Obj-Cที่นี่ฉันเปรียบเทียบสามอินสแตนซ์ (คลาสเป็นประเภทอ้างอิง)
class Person {}
let person = Person()
let person2 = person
let person3 = Person()
person === person2 // true
person === person3 // false
isEqual:
ใน Swift:override func isEqual(_ object: Any?) -> Bool {}
มีรายละเอียดปลีกย่อยที่มี Swifts ===
ที่ไปไกลกว่าเพียงตัวชี้เลขคณิต ในขณะที่ Objective-C คุณสามารถเปรียบเทียบตัวชี้สองตัวใด ๆ (เช่น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 (ตามคำแนะนำของ Jakub Truhlář)
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
แต่การแปลงที่ชัดเจนทำให้ชัดเจนว่าอาจมีบางอย่างเกิดขึ้น ใน String ด้านของสิ่งที่จะยังคงอยู่ตราบใดที่เรา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
มันยังคงสับสนที่มีคลาส String สองคลาส แต่การลดการแปลงโดยนัยอาจทำให้ชัดเจนขึ้นอีกเล็กน้อย
===
Ints
ไม่ได้อยู่ในสวิฟท์ 3
===
ไม่มีความหมายสำหรับ structs เนื่องจากเป็นประเภทค่า โดยเฉพาะอย่างยิ่งมีสามประเภทที่คุณต้องจำไว้: ประเภทตัวอักษรเช่น 1 หรือ "foo" ซึ่งไม่ได้ผูกกับตัวแปรและโดยทั่วไปจะมีผลกับการรวบรวมเท่านั้น ประเภท struct เช่นInt
และString
ซึ่งเป็นสิ่งที่คุณได้รับเมื่อคุณกำหนดตัวอักษรให้กับตัวแปรและชั้นเรียนเช่นและAnyObject
NSString
ตัวอย่างเช่นถ้าคุณสร้างสองอินสแตนซ์ของคลาสเช่นmyClass
:
var inst1 = myClass()
var inst2 = myClass()
คุณสามารถเปรียบเทียบอินสแตนซ์เหล่านั้นได้
if inst1 === inst2
อ้างถึง:
ซึ่งคุณใช้ในการทดสอบว่าวัตถุสองรายการอ้างอิงทั้งสองอ้างถึงอินสแตนซ์วัตถุเดียวกัน
ข้อความที่ตัดตอนมาจาก: Apple Inc. “ ภาษาการเขียนโปรแกรม Swift” iBooks https://itun.es/sk/jEUH0.l
ใน Swift เรามี=== simbol ซึ่งหมายความว่าวัตถุทั้งสองอ้างถึงที่อยู่เดียวกันอ้างอิงเดียวกัน
class SomeClass {
var a: Int;
init(_ a: Int) {
self.a = a
}
}
var someClass1 = SomeClass(4)
var someClass2 = SomeClass(4)
someClass1 === someClass2 // false
someClass2 = someClass1
someClass1 === someClass2 // true
เป็นเพียงการช่วยเหลือเล็กน้อยที่เกี่ยวข้องกับAny
วัตถุ
ฉันทำงานกับการทดสอบหน่วยรอบ ๆNotificationCenter
ซึ่งใช้Any
เป็นพารามิเตอร์ที่ฉันต้องการเปรียบเทียบเพื่อความเท่าเทียมกัน
อย่างไรก็ตามเนื่องจากAny
ไม่สามารถใช้ในการดำเนินการที่เท่าเทียมกันจึงจำเป็นต้องเปลี่ยนแปลง ในที่สุดฉันตัดสินด้วยวิธีการต่อไปนี้ซึ่งทำให้ฉันได้รับความเสมอภาคในสถานการณ์เฉพาะของฉันแสดงที่นี่พร้อมตัวอย่างง่าย ๆ :
func compareTwoAny(a: Any, b: Any) -> Bool {
return ObjectIdentifier(a as AnyObject) == ObjectIdentifier(b as AnyObject)
}
ฟังก์ชั่นนี้ใช้ประโยชน์จากObjectIdentifierซึ่งให้ที่อยู่เฉพาะสำหรับวัตถุทำให้ฉันทดสอบ
หนึ่งรายการที่ควรทราบเกี่ยวกับObjectIdentifier
แอปเปิลที่ลิงค์ด้านบน:
ใน Swift เฉพาะอินสแตนซ์ของคลาสและ metatypes เท่านั้นที่มีตัวตนที่ไม่ซ้ำกัน ไม่มีแนวคิดเกี่ยวกับเอกลักษณ์ของ structs, enums, function หรือ tuples
==
ใช้เพื่อตรวจสอบว่าตัวแปรสองตัวมีค่าเท่ากัน
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!'
==
คือisEqual:
หรือเทียบเท่าระดับความหมายที่กำหนด===
ใน Swift อยู่==
ใน (Obj) C - ตัวชี้ความเท่าเทียมกันหรือตัวตนของวัตถุ