Même jugement / jugement de valeur égale / comparaison / ordre dans Swift et Java

Cet article vise à vous familiariser avec «Equatable» et «Comparable» de Swift. Comme c'est un gros problème, je vais le comparer avec Java.

Swift et Java sont tous deux des nettoyages statiques puissants. «1» n'est pas «1» ». Swift a des types de référence et des types de valeur, et Java a également des types de référence et des types primitifs. Mais Swift ne dit pas "J'ai comparé String avec==> <". Voyons ce qui est identique et ce qui est différent.

Éléments à vérifier

est.

Swift

Même jugement

Utilisez l'opérateur ===. En comparant ʻAnyObject, il peut être utilisé sans implémenter ʻEquatable etc.

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

=== est dans Equatable.swift.

Jugement de valeur égale

Seuls les types qui implémentent ʻEquatable` peuvent effectuer une détermination d'égalité. (error: binary operator '==' cannot be applied)

public protocol Equatable {
  static func == (lhs: Self, rhs: Self) -> Bool
}

Lors de l'implémentation de ʻEquatable, il doit être implémenté de manière à maintenir la substituabilité. Deux instances qui sont égales l'une à l'autre sont compatibles dans le code qui utilise cette valeur. Par conséquent, == devrait considérer tous les aspects visibles du type. Les types ʻEquatable ne doivent exposer aucun aspect sans valeur autre que l'identification de classe, et tout ce qui est exposé doit être documenté.

Si ʻEquatable`, les propriétés suivantes doivent être satisfaites.

De plus, ʻa! = Bdoit être! (A == b)`. Ceci est satisfait du côté de la bibliothèque standard.

extension Equatable {
  @_transparent
  public static func != (lhs: Self, rhs: Self) -> Bool {
    return !(lhs == rhs)
  }
}

Traitement nul

ʻOptional lui-même n'est pas ʻEquatable, mais il y en a quelques == ʻen plus de ceux de ʻEquatable. Le paramètre == utilisé dépend du fait que T est ʻEquatable`.

Lors de la comparaison de nil avec ʻOptional tel que T est ʻEquatable, ce qui suit` == ʻest utilisé.

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

Lors de la comparaison de nil avec ʻOptional où T n'est pas ʻEquatable

@_transparent
public func == <T>(lhs: T?, rhs: _OptionalNilComparisonType) -> Bool {
  switch lhs {
  case .some(_):
    return false
  case .none:
    return true
  }
}

Utiliser. _OptionalNilComparisonType permet à T qui n'est pas ʻEquatable` d'être comparé à nil, et n'est pas utilisé dans le processus de jugement vrai / faux lui-même.

Il est possible de comparer T et nul, mais cela est traité comme un avertissement. (warning: comparing non-optional value of type to nil always returns false)

Gestion des valeurs de hachage

En implémentant Hashable, cela peut être la clé de Dictionary. Hashable hérite de ʻEquatable`.

public protocol Hashable : Equatable {
    var hashValue: Int { get }
}

Pour deux objets a, b, si ʻa == b, alors ʻa.hashValue == b.hashValue doit être. Il n'est pas nécessaire d'avoir ʻa == b lorsque ʻa.hashValue == b.hashValue.

Comparaison avec d'autres types

Limité aux comparaisons du même type par «Soi».

Commande pour taper

La commande aux types se fait en implémentant Comparable. ʻArraya plusieurs méthodes de tri, maismutating func sort ()/func sorted () -> [Element] ne peut être fait que lorsque ʻElement est Comparable.

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
}

Quatre méthodes sont définies, mais si vous implémentez == et < de ʻEquatable`, les trois autres seront couvertes.

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

Cela garantit qu'un seul des éléments ʻa == b / ʻa <b / b <a est vrai.

De plus, l'ordre entier au sens strict est toujours valable.

Le type du côté implémentation peut contenir des valeurs qui sont traitées comme des exceptions et ne sont pas sujettes à comparaison, mais ces valeurs n'ont pas besoin d'être traitées dans l'ordre complet le plus étroit. FloatingPoint.nan renvoie false quelle que soit la manière dont il est comparé.

1.21 > Double.nan        // false
1.21 < Double.nan        // false
1.21 = Double.nan        // false
Double.nan == Double.nan // false

Double.nan.isNaN         // true

Le positionnement est la définition de la méthode de comparaison par défaut, et le tri gratuit est possible en utilisant ʻareInIncreasingOrder`, qui sera introduit plus tard.

Cohérence avec le jugement d'égalité

Oui. Comparable hérite de ʻEquatable`. Ce n'est que lorsqu'il y a un nombre égal qu'on peut parler du nombre inégal.

Traitement nul

Il n'y a aucune comparaison avec zéro.

En passant, il est possible d'implémenter «Comparable» dans «Optionnel», mais il n'est pas possible d'implémenter un protocole pour des contraintes telles que «Optionnel où Wrapped: Equatable». (error: extension with constraints cannot have an inheritance clause)

Comparaison avec d'autres types

Limité aux comparaisons du même type par «Soi».

Commande à ʻArray`

En préparant (Element, Element) throws-> Bool, vous pouvez trier selon la situation.

mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows

Cependant, l'ordre faible au sens étroit doit être établi.

Cohérence avec le jugement d'égalité

Sans limites. Cela dépend de la mise en œuvre.

Traitement nul

Sans limites. S'il est implémenté, ʻArray <Optional > `peut être trié.

Comparaison avec d'autres types

Limité aux comparaisons du même type par (Element, Element).

Jugement par la méthode assert

XCTAssertEqual requiert ʻ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

Il existe une version T? Séparée pour des raisons de sécurité de type.

Java

Même jugement

Utilisez ==.

Jugement de valeur égale

Utilisez la méthode ʻequals. La méthode ʻequals elle-même provient à l'origine de la classe ʻObject`. Cependant, la situation réelle est le même jugement.

public boolean equals(Object obj) {
    return (this == obj);
}

Le côté héritage le remplace et le détermine. Un exemple de «String» est illustré ci-dessous.

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

Méthode ʻEquals`

Il y a.

Traitement de null

Il est censé comparer des objets non nuls. Si l'autre partie est nulle, ce sera faux.

Gestion des valeurs de hachage

Lors de la substitution de la méthode ʻequals, il est également nécessaire de remplacer le public int hashCode () dérivé de ʻObject et de s'en occuper ensemble. Ceci est dû au fait que hashCode a les règles suivantes concernant ʻequals`.

String remplace hashCode comme suit:

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

Comparaison avec d'autres types

Puisque toutes les classes héritent de ʻObject, ʻequals peut être utilisé.

Commande aux classes

Si Comparable <? Super T>, comme méthode de tri pour List <T>

public static <T extends Comparable<? super T>> void sort(List<T> list)

Peut être utilisé. public int compareTo (To) Les éléments suivants doivent être garantis au moment de la mise en œuvre.

Cohérence avec le jugement d'égalité

Lorsque les résultats de ʻe1.compareTo (e2) == 0et ʻe1.equals (e2)correspondent à tous les e1 et e2 de la classe C, on dit qu'il est cohérent avec ʻequals. La cohérence avec ʻequals n'est pas requise, mais il est recommandé d'être cohérent car cela ne garantit pas le comportement des ensembles de tri et des cartes de tri. Un exemple d'incohérence est «BigDecimal».

S'il est incohérent, il est recommandé de l'indiquer.

Traitement de null

On dit qu'une exception doit être levée car null n'est une instance d'aucun objet.

Comparaison avec d'autres types

«Comparable » est

public interface Comparable<T> {
    public int compareTo(T o);
}

Comme vous pouvez le voir, il est possible d'implémenter une comparaison avec un autre type.

Commande à la collection

En préparant Comparator <T>

public static <T> void sort(List<T> list, Comparator<? super T> c)

Peut être trié par.

ʻInt compare (To1, To2) `Ce qui suit doit être garanti lors de l'implémentation.

Cohérence avec le jugement d'égalité

Comparator <T> est cohérent avec ʻequals lorsque les résultats de ʻe1.compareTo (e2) == 0 et ʻe1.equals (e2) `correspondent à tous les e1 et e2 de l'ensemble S Il y a. Là encore, la cohérence est recommandée car le comportement des ensembles de tri et des cartes de tri n'est plus garanti. S'il est incohérent, il vaut mieux le préciser.

Traitement de null

La comparaison avec null est autorisée selon l'option. Pour Comparator <T>

public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator)

Il existe des méthodes comme.

Comparaison avec d'autres types

Il est destiné à la comparaison entre les mêmes types.

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
    //Abréviation
}

Jugement par la méthode assert

Pour les types référence, il existe une méthode assert qui prend ʻObject`.

static public void assertEquals(String message, Object expected, Object actual)

Le traitement est divisé selon que l'objet attendu est nul ou non. S'il est nul, le résultat dépend du fait que réel est nul. S'il n'est pas nul, faites un jugement avec ʻattendu.equals (réel) `.

D'autre part, des méthodes sont préparées pour chaque type primitif. Par exemple, float

static public void assertEquals(String message, float expected, float actual, float delta)

Il y a un Float à l'intérieur

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

Appelle.

La différence entre Swift et Java en un coup d'œil

Swift Java
Même jugement === ==
Jugement de valeur égale == equals
Propriétés imposées au jugement d'égalité Réfléchissant/Symétrie/Transition Réfléchissant/Symétrie/Transition/Cohérence
Comparaison avec null dans le jugement d'égalité Optional<T>Peut être vrai si type Toujours faux
Cohérence des valeurs de hachage lorsqu'elles sont égales HashableObligatoire Obligatoire
Comparaison avec d'autres types dans le jugement d'égalité Impossible Oui
Commande aux classes Comparable (Tout ordre au sens strict) Comparable<T> (Tout ordre au sens strict)
Cohérence de l'ordre des classes et jugement d'égalité Toujours là Recommandation
Comparaison avec null dans l'ordre à la classe Impossible Jet d'exception recommandé
Comparaison avec d'autres types dans l'ordre des classes Impossible Oui
Commande à la collection areInIncreasingOrder (Ordre faible au sens strict) Comparator<T> (Tout ordre au sens strict)
Cohérence de l'ordre et jugement d'égalité à la collecte Aucune mention Recommandation
Comparaison avec null dans l'ordre de collecte Optional<T>Oui Possible selon l'option
Comparaison avec d'autres types dans la commande à la collecte Impossible Impossible
Jugement par la méthode assert Avoir besoinEquatable equalsutilisation

prime

Méthode d'assertion Objective-C

Swift et Objective-C ont des méthodes d'assert différentes.

Quand je l'aligne à nouveau,

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 est plus proche de Java à cet égard.

Règles de commande

À propos de la commande totale stricte au sens étroit et de la commande stricte faible au sens étroit. C'est un terme défini quelque part.

Ce qui est strict et totalement faible est

«Comparable» de Swift est "Non réfléchissant" "Ne pas autoriser l'incomparabilité" ("FloatingPoint.nan" etc. ne sont pas applicables) Par conséquent, il s'agit d'une commande totale stricte.

d'autre part

ʻAreInIncreasingOrder` "Non réfléchissant" "Tolérer l'incomparabilité" "Impossible de faire la transition" Par conséquent, il s'agit d'une commande stricte et faible.

__peut être. __

À propos, les deux «Comparable » et «Comparator » de Java se nomment tous deux un ordre total dans la description de la classe et mentionnent non réfléchissant dans la description de la méthode. En d'autres termes, on peut lire qu'un ordre total strict est supposé.

Pour l'incomparabilité, voir l'élément suivant.

Let's try

L'histoire est appropriée.

Takashi-kun a reçu beaucoup de balles de son frère.

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

La taille et la couleur des boules varient. Y a-t-il la même balle? Je pense que.

extension Ball: Equatable {}

///Satisfaire la réflectivité, la symétrie et la transition
///Toutes les choses visibles ont été tissées
/// (a != b)Quand!(a == b)Correspondance des résultats
func ==(lhs: Ball, rhs: Ball) -> Bool {
    return lhs.diameter == rhs.diameter && lhs.color == rhs.color
}
/**
 *Satisfaire la réflectivité, la symétrie, la transition et la cohérence
 *hashCode a également été remplacé
 *Renvoie false si nul
 */
@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;
}

/**
 *Renvoie le même entier si le diamètre et la couleur n'ont pas changé
 * `equals`Renvoie le même entier s'ils sont égaux
 * `equals`Renvoie des entiers différents si différents
 */
@Override
public int hashCode() {
    return Objects.hash(this.diameter, this.color);
}

Même ainsi, il y en a trop et je ne sais pas quel genre de balle il y a. Afin de trouver la balle à utiliser pour attraper la balle la prochaine fois, j'ai décidé de les organiser par ordre de taille.

let balls: [Ball] = [/*Beaucoup!*/]

balls.sort {
    return $0.diameter < $1.diameter
}
List<Ball> list = Arrays.asList(/*Beaucoup!*/);

//Je ne vais pas autoriser null
list.sort((Ball o1, Ball o2) ->
    o1.diameter - o2.diameter
);

Takashi-kun a toléré l'incomparabilité. Je n'ai pas décidé comment organiser les couleurs, donc je ne peux pas décider comment organiser des boules de la même taille. Considérant (10, bleu) et (10, rouge), (10, bleu) < (10, rouge) est faux et (10, bleu) > (10, rouge) est également faux. Puisque les deux < et > sont faux, (10, bleu) == (10, rouge) est valable. En d'autres termes, les boules de même taille et de même couleur __différence __ sont __même __. C'est une histoire qui ne se produit pas si l'incomparabilité n'est pas tolérée.

L'arrangement qui se concentre uniquement sur cette taille

Est une commande stricte et faible. La requête ʻareInIncreasingOrder de Swift est un ordre strict et faible, donc ça va. Cependant, le «comparateur <T>» de Java ne convient pas car il s'appelle lui-même ordre total. Non seulement cela, mais se concentrer uniquement sur la taille signifie que les résultats de ʻe1.compareTo (e2) == 0 et ʻe1.equals (e2) `ne correspondent pas aux boules de même taille. Faire. Autrement dit, il y a une incohérence entre les méthodes «Comparator » et «equals ».

J'étais content d'aligner les couilles, mais ma mère s'est fâchée et j'ai dû nettoyer. J'ai décidé de faire correspondre la taille et la couleur parce que c'était un gros problème.

extension Ball: Comparable {}

///Satisfait non réfléchissant, asymétrique, transitionnel
func < (lhs: Ball, rhs: Ball) -> Bool {
    if lhs.diameter == rhs.diameter {
        return lhs.color.hashValue < rhs.color.hashValue
    } else {
        return lhs.diameter < rhs.diameter
    }
}
/**
 *Satisfait non réfléchissant, asymétrique, transitionnel
 * `equals`Cohérent avec
 * `o`Jeter un gluant quand est nul
 */
@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 est venu s'aligner en regardant les couleurs. Ceci établit la cohérence avec ʻequals. Bien sûr, il est également cohérent avec ʻEquatable. Suite à la décision correcte de l'ordre des couleurs, les exigences d'une commande totale stricte ont également été remplies. Cela satisfera la demande de Comparable `` Comparable ''.

Les références

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

commande 2004-05-29 - Cry’s Diary algorithme --cpprefjp C ++ Japanese Reference

Recommended Posts

Même jugement / jugement de valeur égale / comparaison / ordre dans Swift et Java
[Java / Swift] Comparaison de l'interface Java et du protocole Swift
Jugement de valeur égale de Integer et int
Comparaison entre Java et Swift (1) Source control / Scope / Variables
Comparaison Java et Swift (3) Implémentation de classe / héritage de classe / conception de classe
StringUtils.isNotBlank est pratique pour un jugement vide et un jugement nul en java
Trier la liste par ordre décroissant en Java et générer une nouvelle liste de manière non destructive
[Java] Obtenez les dates des derniers lundi et dimanche dans l'ordre
Les deux listes Java sont ignorées dans l'ordre, null est ignoré et les doublons sont ignorés.
Classe StringBuffer et StringBuilder en Java
Java passe par valeur et passe par référence
Comprendre equals et hashCode en Java
Bonjour tout le monde en Java et Gradle
Comparaison entre Java et Swift (2) Type de base / Arithmétique / Syntaxe de contrôle / Définition de fonction
Ceci et cela de la mise en œuvre du jugement en temps réel des dates en Java
Comparaison des méthodes d'implémentation de thread en Java et de la méthode d'expression lambda
Comment créer votre propre annotation en Java et obtenir la valeur
Ordre de description des membres dans la convention de codage Java
Concernant la comparaison d'équivalence de type de chaîne en Java
Différence entre final et immuable en Java
Inverser la clé de la valeur dans la carte Java
Un ingénieur Java a comparé Swift, Kotlin et Java.
[Java] Comparaison des méthodes d'opération de la collection et de StringBuilder
Toutes les mêmes chaînes de code de hachage en Java
Différence entre les listes d'arry et les listes liées en Java
Programmer les en-têtes et pieds de page PDF en Java
Apprenez les modèles Flyweight et ConcurrentHashMap en Java
La direction de Java dans "C ++ Design and Evolution"
De Java à C et de C à Java dans Android Studio
Lire et écrire des fichiers gzip en Java
Différence entre int et Integer en Java
Discrimination d'énum dans Java 7 et supérieur
Conversion mutuelle Hex et UIColor avec Swift