Gleiches Urteil / gleichwertiges Urteil / Vergleich / Reihenfolge in Swift und Java

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

Gleiches Urteil

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.

Gleichwertiges Urteil

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.

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)
  }
}

Behandlung von Null

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 " mit "nil", so dass T "Equatable" ist, wird das folgende "==" verwendet.

@_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 ", wobei T nicht "Gleichwertig" ist

@_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)

Umgang mit Hashwerten

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".

Vergleich mit anderen Typen

Beschränkt auf Vergleiche des gleichen Typs durch "Selbst".

Bestellung zum Tippen

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.

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.

Übereinstimmung mit dem Gleichstellungsurteil

Ja. Comparable erbt von Equatable. Nur wenn es eine gleiche Anzahl gibt, können wir über die ungleiche Anzahl sprechen.

Behandlung von Null

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)

Vergleich mit anderen Typen

Beschränkt auf Vergleiche des gleichen Typs durch "Selbst".

Bestellung zu 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.

Übereinstimmung mit dem Gleichstellungsurteil

Keine Begrenzung. Das hängt von der Implementierung ab.

Behandlung von Null

Keine Begrenzung. Wenn implementiert, ist es möglich, "Array <Optional >" zu sortieren.

Vergleich mit anderen Typen

Beschränkt auf Vergleiche des gleichen Typs durch "(Element, Element)".

Beurteilung nach Assert-Methode

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

Gleiches Urteil

Verwenden Sie ==.

Gleichwertiges Urteil

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

Es gibt.

Behandlung von Null

Es soll Nicht-Null-Objekte vergleichen. Wenn die andere Partei null ist, ist dies falsch.

Umgang mit Hashwerten

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.

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;
}

Vergleich mit anderen Typen

Sie können "gleich" verwenden, da alle Klassen "Objekt" erben.

Bestellung zu Klassen

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.

Übereinstimmung mit dem Gleichstellungsurteil

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.

Behandlung von Null

Es wird gesagt, dass eine Ausnahme ausgelöst werden sollte, da null keine Instanz eines Objekts ist.

Vergleich mit anderen Typen

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.

Bestellung zur Abholung

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.

Übereinstimmung mit dem Gleichstellungsurteil

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.

Behandlung von Null

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.

Vergleich mit anderen Typen

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
}

Beurteilung nach Assert-Methode

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.

Der Unterschied zwischen Swift und Java auf einen Blick

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 HashableErforderlich 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 equalsverwenden

Bonus

Objective-C-Assert-Methode

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.

Bestellregeln

Ü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 " und der Methode "equals".

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 " erfüllen.

Verweise

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

Recommended Posts

Gleiches Urteil / gleichwertiges Urteil / Vergleich / Reihenfolge in Swift und Java
[Java / Swift] Vergleich von Java-Schnittstelle und Swift-Protokoll
Gleichwertige Beurteilung von Integer und int
Vergleich zwischen Java und Swift (1) Quellcodeverwaltung / Umfang / Variablen
Java- und Swift-Vergleich (3) Klassenimplementierung / Klassenvererbung / Klassendesign
StringUtils.isNotBlank eignet sich für Leerurteile und Nullurteile in Java
Sortieren Sie die Liste in absteigender Reihenfolge in Java und generieren Sie zerstörungsfrei eine neue Liste
[Java] Ordnen Sie die Daten des vergangenen Montags und Sonntags der Reihe nach an
Java Zwei Listen werden der Reihe nach ignoriert, null wird ignoriert und Duplikate werden ignoriert.
StringBuffer- und StringBuilder-Klasse in Java
Java als Wert übergeben und als Referenz übergeben
Verstehe gleich und hashCode in Java
Hallo Welt in Java und Gradle
Vergleich zwischen Java und Swift (2) Grundtyp / Arithmetik / Steuerungssyntax / Funktionsdefinition
Dies und das der Implementierung der zeitlichen Beurteilung von Daten in Java
Vergleich der Thread-Implementierungsmethoden in Java und der Lambda-Ausdrucksmethode
So erstellen Sie Ihre eigene Anmerkung in Java und erhalten den Wert
Reihenfolge der Mitgliederbeschreibung in der Java-Codierungskonvention
In Bezug auf den Vergleich der Zeichenfolgentypäquivalenz in Java
Unterschied zwischen final und Immutable in Java
Schlüssel vom Wert in Java Map umkehren
Ein Java-Ingenieur verglich Swift, Kotlin und Java.
[Java] Vergleich von Sammlungs- und StringBuilder-Operationsmethoden
Alle gleichen Hash-Code-Zeichenfolgen in Java
Unterschied zwischen Arrylist und verknüpfter Liste in Java
Programmieren Sie PDF-Kopf- und Fußzeilen in Java
Lernen Sie Flyweight-Muster und ConcurrentHashMap in Java
Die Richtung von Java in "C ++ Design and Evolution"
Von Java nach C und von C nach Java in Android Studio
Lesen und Schreiben von GZIP-Dateien in Java
Unterschied zwischen int und Integer in Java
Diskriminierung von Enum in Java 7 und höher
Hex und UIColor wechselseitige Konvertierung mit Swift