2016-01-27 3 views
2

рассмотрит следующий упрощенный фрагмент кода:Как сравнить общие объекты в Swift?

class Foo<T: Equatable> { 
    var x: T 
    init(_ x: T, _ y: T) { 
     self.x = x 
     if (x == y) { 
      // do something 
     } 
    } 
} 

Я хотел бы этот класс работать для всех видов T с, которые как-то сопоставимы. В идеале он сравнивал бы тождества, если T является объектом и напрямую сравнивает все остальное, что соответствует Equatable.
Приведенный выше код не работает, например, для Array. Если я изменю Equatable на AnyObject и == до ===, то это не сработает для Int s. Как решить эту проблему? Я думал о создании своего собственного протокола, но потом не мог понять, как его реализовать для всех типов, которые соответствуют Equatable.

Edit:
Я не знал, что он будет работать на Mac, потому что я нахожусь на Linux, и когда я пытаюсь скомпилировать

Foo<[Int]>([1, 2], [1, 2]) 

Я получаю следующее сообщение об ошибке:

error: type '[Int]' does not conform to protocol 'Equatable' 
Foo<[Int]>([1, 2], [1, 2]) 
^ 
+1

Что вы имеете в виду «не работает «? Он не будет компилироваться, если вы попытаетесь инициализировать его массивами? Каково сообщение об ошибке? – nhgrif

+1

@nhgrif Общий массив не может быть равным, в прямом смысле, а скорее содержать элементы, которые являются равнозначными. Но я согласен снова прочитать Q, что это неясно (это было, однако, моя интерпретация Q). – dfri

+0

Используя код в вопросе, я могу назвать этот код: 'let f1 = Foo ([1,2,3], [1,2,3])', который отлично работает (и говорит, что они равны). Почему это не работает? Более того, даже если массив имеет несколько типов, например: 'let f1 = Foo ([" string ", 2,3.14], [" string ", 2,3.14])' он работает отлично (и говорит, что они равны). – nhgrif

ответ

1

Простым решением было бы просто добавить еще один инициализатор для массивов Equatable элементов.

class Foo<T: Equatable> { 
    init(_ x: T, _ y: T) { 
     if (x == y) { 
      print("Initialization by equal equatable types.") 
     } 
    } 

    init(_ x: [T], _ y: [T]) { 
     if (x == y) { 
      print("Initialization by equal arrays of equatable types.") 
     } 
    } 
} 

let a = Foo<Int>(1, 1) 
    /* Initialization by equal equatable types. */ 
let b = Foo<Int>([1, 2, 3], [1, 2, 3]) 
    /* Initialization by equal arrays of equatable types. */ 
+0

Я, вероятно, немного упростил свой код. Переменные, которые я сравниваю, являются фактически сохраненными свойствами, поэтому я не могу просто перегрузить конструктор. – eyelash

-1

В зависимости от того, что вы собираетесь делать с Foo, он не может быть необходимо, чтобы сделать это универсальный класс, а просто общие инициализаторами:

class Foo 
{ 
    init<T:Equatable>(_ x: T, _ y: T) 
    { 
     if (x == y) 
     { 
      // do something 
     } 
    } 

    init<T:AnyObject>(_ x: T, _ y: T) 
    { 
     if (x === y) 
     { 
      // do something 
     } 
    } 
} 

// in Playground ... 

class Bar { } 

let C = Foo(3,4) // no error 

let O1 = Bar() 
let O2 = Bar() 

let D = Foo(O1,O2) // no error 
+0

Это не сработает. '' AnyObject' сам соответствует 'Equatable' и как таковой, каждый раз, когда вы пытаетесь инициализировать' Foo' чем-либо, унаследованным от 'AnyObject', вы получите сообщение об ошибке:' Неоднозначное использование 'init''. – nhgrif