2015-10-27 9 views
9

Perché l'ultima istruzione non riescono a compilare con l'errore: Binary operator '==' cannot be applied to two '[[Simple]]’ operands, e c'è un modo modo per modificare la Simple struct o estendere l'operatore == di essere in grado di eseguire i controlli di uguaglianza su matrici nidificate (o dizionari)?Swift operatore di uguaglianza su matrici nidificate

var i1: [Int] = [1] 
var i2: [Int] = [1] 
i1 == i2 // -> true 


var i3: [[Int]] = [[1], [2]] 
var i4: [[Int]] = [[1], [2]] 
i3 == i4 // -> true 


struct Simple: Equatable, Hashable { 
    let message: String 

    var hashValue: Int { 
     return message.hashValue 
    } 
} 
func ==(lhs: Simple, rhs: Simple) -> Bool { 
    return lhs.message == rhs.message 
} 

var a: [Simple] = [Simple(message: "a")] 
var b: [Simple] = [Simple(message: "a")] 
a == b // -> true 

var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]] 
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]] 
x == y // -> ERROR! Binary operator '==' cannot be applied to two '[[Simple]]’ operands 

risposta

14

La ragione è simile come in Why is Equatable not defined for optional arrays. Gli array possono essere confrontati con == se il tipo di elemento è Equatable:

/// Returns true if these arrays contain the same elements. 
public func ==<Element : Equatable>(lhs: [Element], rhs: [Element]) -> Bool 

Ecco perché

var a: [Simple] = [Simple(message: "a")] 
var b: [Simple] = [Simple(message: "a")] 
a == b // -> true 

compila.

Ma anche per i tipi equatable T, Array<T>non è conforme al protocolloEquatable, confrontare Why can't I make Array conform to Equatable?. Pertanto, in

var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]] 
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]] 
x == y // -> ERROR! Binary operator '==' cannot be applied to two '[[Simple]]’ operands 

x e y sono array con il tipo di elemento [Simple] che fa non conformi al protocollo Equatable, e non c'è corrispondenza == operatore.

è possibile definire una generica == operatore per gli array semplicemente annidati come

func ==<Element : Equatable> (lhs: [[Element]], rhs: [[Element]]) -> Bool { 
    return lhs.count == rhs.count && !zip(lhs, rhs).contains {$0 != $1 } 
} 

o più semplicemente (come suggerito da @kennytm):

func ==<Element : Equatable> (lhs: [[Element]], rhs: [[Element]]) -> Bool { 
    return lhs.elementsEqual(rhs, by: ==) 
} 

Questo rende x == y compilazione e il lavoro come previsto. Allo stato attuale, sembra che non sia un modo per definire un operatore == su matrici arbitrariamente annidate.

Note:

  • Come di Swift 4.1 (attualmente in fase di sviluppo, snapshots available):

    The standard library types Optional, Array, and Dictionary now conform to the Equatable protocol when their element types conform to Equatable. ...

    (dalla Swift CHANGELOG). Ciò rende obsoleta la soluzione precedente.

  • La conformità condizionale generale, come proposto in SE-0143 Conditional conformances, non è stata ancora implementata.

+0

Forse aggiornare l'implementazione a 'lhs.elementsEqual (rhs, di: ==)'? – kennytm

+0

@kennytm: buon suggerimento, grazie! –

+0

Suggerimento: poiché https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md non è stato incluso in Swift 4, aggiornare la risposta –

1

È possibile farlo mediante l'attuazione di una funzione == per esso, come segue:

func == (lhs: [[Simple]], rhs: [[Simple]]) -> Bool { 
    //your code 
} 
+0

Ci scusiamo per il voto negativo, ma questa domanda è molto più complicata di quanto implichi la risposta. – Jeff

+0

@Jeff Hai diritto alla tua opinione ma preferisco sempre soluzioni semplici a quelle complicate. [YAGNI] (https://en.wikipedia.org/wiki/You_aren't_gonna_need_it) si applica qui. – Adam

+0

Il mio commento non riguardava preferire una risposta inutilmente complessa. La tua risposta non è una soluzione a questa domanda. La tua risposta è incompleta. La domanda è più complessa di quanto sembri capire. – Jeff