Dieser Artikel soll Sie mit Swifts "Equatable" und "Comparable" vertraut machen. Da es eine große Sache ist, werde ich es mit Java vergleichen.
Sowohl Swift als auch Java sind starke statische Bereinigungen. "1" ist nicht "1". Swift hat Referenztypen und Werttypen, und Java hat auch Referenztypen und primitive Typen. Aber Swift sagt nicht "Ich habe" String "mit" == "> <" verglichen. Mal sehen, was gleich und was anders ist.
Zu überprüfende Elemente
ist.
Swift
Verwenden Sie den Operator ===
. Es kann verwendet werden, indem "AnyObject" verglichen wird, ohne "Equatable" usw. zu implementieren.
public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return Bool(Builtin.cmp_eq_RawPointer(
Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(l)),
Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(r))
))
case (nil, nil):
return true
default:
return false
}
}
===
ist in Equatable.swift.
Nur Typen, die "Equatable" implementieren, können eine Gleichheitsbestimmung durchführen. (error: binary operator '==' cannot be applied)
public protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
Bei der Implementierung von "Equatable" sollte es implementiert werden, um die Substituierbarkeit aufrechtzuerhalten. Zwei einander gleiche Instanzen sind in Code kompatibel, der diesen Wert verwendet. Daher sollte ==
alle sichtbaren Aspekte des Typs berücksichtigen. Typen, die "gleichwertig" sind, sollten keine anderen wertlosen Aspekte als die Klassenidentifikation offenlegen, und alles, was offengelegt wird, sollte dokumentiert werden.
Wenn "Equatable", müssen die folgenden Eigenschaften erfüllt sein.
a == a
ist immer wahr)b == a
wenn a == b
)a == b
und b == c
dann a == c
)Außerdem muss "a! = B" "! (A == b)" sein. Dies ist auf der Seite der Standardbibliothek erfüllt.
extension Equatable {
@_transparent
public static func != (lhs: Self, rhs: Self) -> Bool {
return !(lhs == rhs)
}
}
Optional <T>
selbst ist nicht Equatable
, aber es gibt einige ==
zusätzlich zu denen von Equatable
. Welches ==
verwendet wird, hängt davon ab, ob T Equatable
ist.
Beim Vergleich von "Optional
@_inlineable
public func == <T: Equatable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l == r
case (nil, nil):
return true
default:
return false
}
}
Beim Vergleich von Null mit "Optional
@_transparent
public func == <T>(lhs: T?, rhs: _OptionalNilComparisonType) -> Bool {
switch lhs {
case .some(_):
return false
case .none:
return true
}
}
Benutzen. _OptionalNilComparisonType
ermöglicht den Vergleich von T, das nicht Equatable
ist, mit nil und wird nicht im True / False-Beurteilungsprozess selbst verwendet.
Es ist möglich, T und Null zu vergleichen, dies wird jedoch als Warnung behandelt. (warning: comparing non-optional value of type to nil always returns false)
Durch die Implementierung von "Hashable" kann es der Schlüssel von "Dictionary" sein.
Hashable
erbt von Equatable
.
public protocol Hashable : Equatable {
var hashValue: Int { get }
}
Für zwei beliebige Objekte a, b muss, wenn "a == b", "a.hashValue == b.hashValue" sein. Es ist nicht erforderlich, "a == b" zu haben, wenn "a.hashValue == b.hashValue".
Beschränkt auf Vergleiche des gleichen Typs durch "Selbst".
Die Bestellung nach Typen erfolgt durch Implementierung von Comparable
. Es gibt verschiedene Sortiermethoden in Array
, aber Mutting func sort ()
/ func sorted () -> [Element]
kann nur ausgeführt werden, wenn Element
Comparable
ist.
public protocol Comparable : Equatable {
static func < (lhs: Self, rhs: Self) -> Bool
static func <= (lhs: Self, rhs: Self) -> Bool
static func >= (lhs: Self, rhs: Self) -> Bool
static func > (lhs: Self, rhs: Self) -> Bool
}
Es sind vier Methoden definiert, aber wenn Sie "==" und "<" von "Equatable" implementieren, werden die verbleibenden drei behandelt.
extension Comparable {
public static func > (lhs: Self, rhs: Self) -> Bool {
return rhs < lhs
}
public static func <= (lhs: Self, rhs: Self) -> Bool {
return !(rhs < lhs)
}
public static func >= (lhs: Self, rhs: Self) -> Bool {
return !(lhs < rhs)
}
}
Dies stellt sicher, dass nur eines von "a == b" / "a <b" / "b <a" wahr ist.
Außerdem gilt immer die gesamte Ordnung im engeren Sinne.
a <a
ist immer falsch)! (B <a)
wenn a <b
)a <c
wenn a <b
und b <c
)Der Typ auf der implementierenden Seite kann Werte enthalten, die als Ausnahmen behandelt werden und keinem Vergleich unterliegen, aber solche Werte müssen nicht in der engeren vollständigen Reihenfolge behandelt werden.
FloatingPoint.nan
gibt false zurück, egal wie es verglichen wird.
1.21 > Double.nan // false
1.21 < Double.nan // false
1.21 = Double.nan // false
Double.nan == Double.nan // false
Double.nan.isNaN // true
Die Positionierung ist die Definition der Standardvergleichsmethode, und die freie Sortierung ist mithilfe von "areInIncreasingOrder" möglich, das später eingeführt wird.
Ja. Comparable
erbt von Equatable
. Nur wenn es eine gleiche Anzahl gibt, können wir über die ungleiche Anzahl sprechen.
Es gibt keinen Vergleich mit Null.
Übrigens ist es möglich, "Vergleichbar" in "Optional" zu implementieren, aber es ist nicht möglich, ein Protokoll für eingeschränkte Protokolle wie "Optional, wo verpackt: Gleichwertig" zu implementieren. (error: extension with constraints cannot have an inheritance clause)
Beschränkt auf Vergleiche des gleichen Typs durch "Selbst".
Array
Durch Vorbereiten von (Element, Element) throw-> Bool
können Sie nach der Situation sortieren.
mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows
Die schwache Ordnung im engeren Sinne muss jedoch festgestellt werden.
areInIncreasingOrder (a, a)
ist immer falsch)areInIncreasingOrder (a, b)
und areInIncreasingOrder (b, c)
ifareIncreasingOrder (a, c)
)Keine Begrenzung. Das hängt von der Implementierung ab.
Keine Begrenzung. Wenn implementiert, ist es möglich, "Array <Optional
Beschränkt auf Vergleiche des gleichen Typs durch "(Element, Element)".
XCTAssertEqual
fordert Equatable
an.
func XCTAssertEqual<T>(
_ expression1: @autoclosure () throws -> T,
_ expression2: @autoclosure () throws -> T,
_ message: @autoclosure () -> String = default,
file: StaticString = #file,
line: UInt = #line
) where T : Equatable
Aus Sicherheitsgründen gibt es eine separate T-Version.
Java
Verwenden Sie ==
.
Verwenden Sie die Methode "equals". Die Methode "equals" selbst stammt ursprünglich aus der Klasse "Object". Die tatsächliche Situation ist jedoch das gleiche Urteil.
public boolean equals(Object obj) {
return (this == obj);
}
Die Vererbungsseite überschreibt dies und bestimmt es. Ein Beispiel für "String" ist unten gezeigt.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Für die "Gleich" -Methode
x.equals (x) == true
)y.equals (x) == true
wenn x.equals (y) == true
)x.equals (y) == true
und y.equals (z) == true
wenn x.equals (z) == true
)Es gibt.
Es soll Nicht-Null-Objekte vergleichen. Wenn die andere Partei null ist, ist dies falsch.
Wenn Sie die Methode "equals" überschreiben, müssen Sie auch den "public int hashCode ()" überschreiben, der ebenfalls vom "Object" abgeleitet ist, und sich gemeinsam darum kümmern. Dies liegt daran, dass hashCode
die folgenden Regeln bezüglich equals
hat.
hashCode
gibt immer dieselbe Ganzzahl zurück, wenn sich die im Vergleich mit der equals
-Methode verwendeten Informationen nicht geändert haben.String
überschreibt hashCode
wie folgt:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
Sie können "gleich" verwenden, da alle Klassen "Objekt" erben.
Wenn Comparable <? Super T>
, als Sortiermethode für List <T>
public static <T extends Comparable<? super T>> void sort(List<T> list)
Kann verwendet werden.
public int compareTo (To)
Folgendes muss zum Zeitpunkt der Implementierung garantiert sein.
sgn (x.compareTo (y)) == -sgn (y.compareTo (x))
(x.compareTo (y)> 0 && y.compareTo (z)> 0)
, dann x.compareTo (z)> 0
Wenn die Ergebnisse von "e1.compareTo (e2) == 0" und "e1.equals (e2)" für alle e1 und e2 der Klasse C übereinstimmen, wird gesagt, dass sie mit "gleich" übereinstimmen. Die Konsistenz mit "gleich" ist nicht erforderlich, es wird jedoch empfohlen, konsistent zu sein, da dies das Verhalten von Sortiersätzen und Sortierkarten nicht garantiert. Ein Beispiel für Inkonsistenz ist "BigDecimal".
Wenn es inkonsistent ist, wird empfohlen, dies anzugeben.
Es wird gesagt, dass eine Ausnahme ausgelöst werden sollte, da null keine Instanz eines Objekts ist.
Vergleichbares <T>
ist
public interface Comparable<T> {
public int compareTo(T o);
}
Wie Sie sehen, ist es möglich, einen Vergleich mit einem anderen Typ durchzuführen.
Durch Vorbereitung von "Comparator
public static <T> void sort(List<T> list, Comparator<? super T> c)
Kann sortiert werden nach.
int compare (To1, To2)
Folgendes muss zum Zeitpunkt der Implementierung garantiert sein.
sgn (vergleiche (x, y)) == -sgn (vergleiche (y, x))
((vergleiche (x, y)> 0) && (vergleiche (y, z)> 0))
dann vergleiche (x, z)> 0
Comparator <T>
stimmt mit equals
überein, wenn die Ergebnisse von e1.compareTo (e2) == 0
unde1.equals (e2)
für alle e1 und e2 in Satz S übereinstimmen Es gibt.
Auch hier wird Konsistenz empfohlen, da das Verhalten von Sortiersätzen und Sortierzuordnungen nicht mehr garantiert ist. Wenn es inkonsistent ist, ist es besser, es anzugeben.
Der Vergleich mit null ist je nach Option zulässig.
Für Komparator <T>
public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator)
Es gibt Methoden wie.
Es ist zum Vergleich zwischen den gleichen Typen gedacht.
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
//Abkürzung
}
Für Referenztypen gibt es eine Assert-Methode, die "Object" verwendet.
static public void assertEquals(String message, Object expected, Object actual)
Die Verarbeitung wird aufgeteilt, je nachdem, ob "Objekt erwartet" null ist oder nicht. Wenn es null ist, hängt das Ergebnis davon ab, ob tatsächlich null ist. Wenn es nicht null ist, wird das Urteil mit "expected.equals (actual)" getroffen.
Andererseits werden Methoden für jeden primitiven Typ vorbereitet. Zum Beispiel "float"
static public void assertEquals(String message, float expected, float actual, float delta)
Im Inneren befindet sich ein "Float"
public static int compare(float f1, float f2) {
if (f1 < f2)
return -1; // Neither val is NaN, thisVal is smaller
if (f1 > f2)
return 1; // Neither val is NaN, thisVal is larger
// Cannot use floatToRawIntBits because of possibility of NaNs.
int thisBits = Float.floatToIntBits(f1);
int anotherBits = Float.floatToIntBits(f2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
Ruft an.
Swift | Java | |
---|---|---|
Gleiches Urteil | === |
== |
Gleichwertiges Urteil | == |
equals |
Eigenschaften, die dem Gleichstellungsurteil auferlegt werden | Reflektierend/Symmetrie/Überleitung | Reflektierend/Symmetrie/Überleitung/Konsistenz |
Vergleich mit Null im Gleichheitsurteil | Optional<T> Kann wahr sein, wenn Typ |
Immer falsch |
Konsistenz der Hashwerte, wenn sie gleich sind | Hashable Erforderlich |
Verpflichtend |
Vergleich mit anderen Typen im Gleichstellungsurteil | Unmöglich | Ja |
Bestellung zu Klassen | Comparable (Alle Ordnung im engeren Sinne) |
Comparable<T> (Alle Ordnung im engeren Sinne) |
Konsistenz der Reihenfolge nach Klassen und Gleichheitsbeurteilung | Immer da | Empfehlung |
Vergleich mit null bei der Bestellung zur Klasse | Unmöglich | Ausnahmewurf empfohlen |
Vergleich mit anderen Typen bei der Bestellung zu Klassen | Unmöglich | Ja |
Bestellung zur Abholung | areInIncreasingOrder (Schwache Ordnung im engeren Sinne) |
Comparator<T> (Alle Ordnung im engeren Sinne) |
Konsistenz der Reihenfolge und Gleichheitsbeurteilung zur Sammlung | Nicht erwähnenswert | Empfehlung |
Vergleich mit null bei der Bestellung zur Abholung | Optional<T> Ja |
Möglich je nach Option |
Vergleich mit anderen Typen bei der Bestellung zur Abholung | Unmöglich | Unmöglich |
Beurteilung nach Assert-Methode | BrauchenEquatable |
equals verwenden |
Swift und Objective-C haben unterschiedliche Assert-Methoden.
Wenn ich es wieder aufstelle,
func XCTAssertEqual<T>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) where T : Equatable
func XCTAssertEqual<T>(_ expression1: @autoclosure () throws -> T?, _ expression2: @autoclosure () throws -> T?, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) where T : Equatable
XCTAssertEqual(expression1, expression2, ...)
XCTAssertEqualObjects(expression1, expression2, ...)
static public void assertEquals(String message, float expected, float actual, float delta)
static public void assertEquals(String message, Object expected, Object actual)
ObjC ist in dieser Hinsicht näher an Java.
Über strenge Gesamtordnung im engeren Sinne und strenge schwache Ordnung im engeren Sinne. Es ist irgendwo ein bestimmter Begriff.
Was streng und total schwach ist, ist
Swifts "Vergleichbar" ist
"Nicht reflektierend"
"Unvergleichbarkeit nicht zulassen" (FloatingPoint.nan
usw. sind nicht anwendbar)
Daher ist es eine strikte Gesamtbestellung.
auf der anderen Seite
areInIncreasingOrder
ist
"Nicht reflektierend"
"Unvergleichbarkeit tolerieren"
"Übergang unmöglich"
Daher ist es streng schwache Reihenfolge.
__vielleicht. __ __
Übrigens nennen sich Javas Comparable <T>
und Comparator <T>
beide in der Klassenbeschreibung als Gesamtreihenfolge und erwähnen in der Methodenbeschreibung nicht reflektierend. Mit anderen Worten kann gelesen werden, dass eine strikte Gesamtreihenfolge angenommen wird.
Informationen zur Unvergleichlichkeit finden Sie im nächsten Punkt.
Let's try
Die Geschichte ist angemessen.
Takashi-kun hat viele Bälle von seinem Bruder bekommen.
struct Ball {
let diameter: Int
let color: Color
enum Color {
case blue
case red
case yellow
}
}
class Ball {
int diameter;
Color color;
public Ball(int diameter, Color color) {
this.diameter = diameter;
this.color = color;
}
enum Color {
BLUE, RED, YERROW
}
}
Die Größe und Farbe der Kugeln variieren. Gibt es den gleichen Ball? Ich denke, dass.
extension Ball: Equatable {}
///Erfüllen Sie Reflexionsvermögen, Symmetrie und Übergang
///Alle sichtbaren Dinge wurden gewebt
/// (a != b)Wann!(a == b)Ergebnisse stimmen überein
func ==(lhs: Ball, rhs: Ball) -> Bool {
return lhs.diameter == rhs.diameter && lhs.color == rhs.color
}
/**
*Erfüllen Sie Reflexionsvermögen, Symmetrie, Übergang und Konsistenz
*hashCode wurde ebenfalls überschrieben
*Gibt false zurück, wenn null
*/
@Override
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof Ball) {
Ball anotherBall = (Ball)anObject;
return this.diameter == anotherBall.diameter && this.color == anotherBall.color;
}
return false;
}
/**
*Gibt dieselbe Ganzzahl zurück, wenn sich Durchmesser und Farbe nicht geändert haben
* `equals`Gibt dieselbe Ganzzahl zurück, wenn sie gleich sind
* `equals`Gibt unterschiedliche Ganzzahlen zurück, wenn diese unterschiedlich sind
*/
@Override
public int hashCode() {
return Objects.hash(this.diameter, this.color);
}
Trotzdem gibt es zu viele und ich weiß nicht, was für ein Ball es gibt. Um den Ball zu finden, mit dem ich ihn das nächste Mal fangen kann, habe ich beschlossen, ihn in der Reihenfolge seiner Größe anzuordnen.
let balls: [Ball] = [/*Viele!*/]
balls.sort {
return $0.diameter < $1.diameter
}
List<Ball> list = Arrays.asList(/*Viele!*/);
//Ich werde nicht null zulassen
list.sort((Ball o1, Ball o2) ->
o1.diameter - o2.diameter
);
Takashi-Kun tolerierte Unvergleichlichkeit. Ich habe nicht entschieden, wie die Farben angeordnet werden sollen, daher kann ich nicht entscheiden, wie Bälle gleicher Größe angeordnet werden sollen.
Unter Berücksichtigung von (10, blau) und (10, rot) ist (10, blau) <
(10, rot) falsch und (10, blau) >
(10, rot) ist ebenfalls falsch. Da sowohl "<" als auch ">" falsch sind, gilt (10, blau) "==" (10, rot). Mit anderen Worten, Kugeln gleicher Größe und Farbe __ Unterschied __ sind __ gleich __. Dies ist eine Geschichte, die nicht auftritt, wenn Unvergleichbarkeit nicht toleriert wird.
Die Anordnung, die sich nur auf diese Größe konzentriert
Ist streng schwache Reihenfolge. Swifts "areInIncreasingOrder" -Anforderung ist eine streng schwache Reihenfolge, daher ist es in Ordnung.
Javas Comparator <T>
passt jedoch nicht, da er sich selbst als Gesamtreihenfolge bezeichnet. Nicht nur das, sondern nur die Konzentration auf die Größe bedeutet, dass die Ergebnisse von "e1.compareTo (e2) == 0" und "e1.equals (e2)" nicht für Bälle derselben Größe übereinstimmen. Machen. Das heißt, es besteht eine Inkonsistenz zwischen der Methode "Comparator
Ich war glücklich, die Bälle auszurichten, aber meine Mutter wurde wütend und ich musste aufräumen. Ich entschied mich für Größe und Farbe, weil es eine große Sache war.
extension Ball: Comparable {}
///Befriedigen Sie nicht reflektierend, asymmetrisch, vorübergehend
func < (lhs: Ball, rhs: Ball) -> Bool {
if lhs.diameter == rhs.diameter {
return lhs.color.hashValue < rhs.color.hashValue
} else {
return lhs.diameter < rhs.diameter
}
}
/**
*Befriedigen Sie nicht reflektierend, asymmetrisch, vorübergehend
* `equals`In Übereinstimmung mit
* `o`Wirf einen schleimigen, wenn null ist
*/
@Override
public int compareTo(Ball o) {
if (this.diameter == o.diameter) {
return this.color.hashCode() - o.color.hashCode();
} else{
return this.diameter - o.diameter;
}
}
Takashi-kun stellte sich an, indem er sich die Farben ansah. Dies stellt die Übereinstimmung mit "gleich" her. Natürlich stimmt es auch mit "Equatable" überein.
Durch die richtige Entscheidung über die Reihenfolge der Farben wurden auch die Anforderungen für eine strikte Gesamtreihenfolge erfüllt. Dies wird die Anforderung von entweder "Vergleichbar" "Vergleichbar
Java jdk8/jdk8/jdk: 687fd7c7986d /src/share/classes/ java.lang (Java Platform SE 8) java.util (Java Platform SE 8) Assert (JUnit API)
Apple Swift Standard Library | Apple Developer Documentation apple/swift: The Swift Programming Language [swift-evolution] [Draft][Proposal] Formalized Ordering
bestellen 2004-05-29 - Cry’s Diary Algorithmus --cpprefjp C ++ Japanese Reference