Подтвердить что ты не робот

Сравнение общих типов структур

Как определить, имеют ли два экземпляра общей структуры одного типа?

Например, с учетом следующей структуры:

struct FooBar<T> {
    let variable: T
    init(arg: T) {
        variable = arg
    }
}

И следующий фрагмент:

let foo = FooBar(1)
let bar = FooBar(1.0)
let baz = FooBar("1")

Как определить, являются ли теги foo, bar или baz одинаковыми или разными?


func areExactType(x: FooBar) -> Bool {
    return self.dynamicType === x.dynamicType
}

Это дает

Тип 'Foo' не соответствует протоколу 'AnyObject'


func areExactType(x: FooBar) -> Bool {
    return self.dynamicType === x.dynamicType
}

Это дает

Невозможно вызвать '==' с помощью списка аргументов типа '(Foo.Type, Foo.Type)'


func areExactType(x: FooBar) -> Bool {
    return self is x.dynamicType
}

Это дает три ошибки:

Последовательные операторы строки должны быть разделены символом ';'

(он хочет поставить точку с запятой между периодом и "dynamicType" )

Ожидаемый идентификатор в точечном типе

и

Ожидаемое выражение

4b9b3361

Ответ 1

Взяв некоторое вдохновение из ответа Себастьяна, я придумал это решение:

func sameType<L,R>(left: L, right: R) -> Bool {
    if let cast = left as? R {
        return true
    } else {
        return false
    }
}

Это работает, даже если оно вложено внутри функции, принимающей дженерики:

func compare<T,U>(foo: T, bar: U) -> Bool {
    return sameType(foo, bar)
}

Но у него есть некоторые недостатки, о которых упоминал Себастьян. А именно, если вы извлекли свои значения из коллекции Objective-C, они оба будут иметь тип AnyObject. Более того, если мы вложим мою функцию sameType в функцию, аргументы которой не являются дженериками, например:

func compare(foo: Any, bar: Any) -> Bool {
    return sameType(foo, bar)
}

Функция sameType здесь всегда будет возвращать true. Тип foo и bar, что касается sameType, это Any, а не какой-либо конкретный тип I, который мог бы скрыть его.


Также, вероятно, стоит отметить, что если я попытаюсь вставить это как метод экземпляра, произойдет сбой Xcode. Прочтите это снова, Ошибка Xcode. Не "создает нежелательные результаты". Приложение аварийно завершает работу.

Например:

func sameType<L,R>(left: L, right: R) -> Bool {
    if let cast = left as? R {
        return true
    } else {
        return false
    }
}

struct Foo<T> {
    func sameType<U>(bar: U) -> Bool {
        return sameType(self, bar)
    }
}

let x = Foo<Int>()
let y = Foo<Float>()

if x.sameType(y) {
    println("x is a y")
}

Этот фрагмент кода вызывает ошибки Xcode. Я понятия не имею, почему... но это так...

Если мы вместо этого напишем:

if sameType(x,y) {
    println("x is a y")
}

Xcode компилируется и работает просто отлично.

Ответ 2

Изменить:

Извините за преждевременный ответ, он на самом деле не работает, потому что компилятор будет выбирать функцию для разных типов при вызове из другой функции:

func foobar<T,U> (lhs: Foo<T>, rhs: Foo<U>) -> Bool {
    return lhs.sameType(rhs)
}

Если вы останетесь на чистой территории Свифта, будет работать следующее:

Учитывая простую общую структуру

struct Foo<T> {
    let v : T
}

Вы можете определить функцию sameType, которая принимает значение Foo того же типа и просто возвращает true:

func sameType<T> (a: Foo<T>, b: Foo<T>) -> Bool {
    return true
}

и перегрузите функцию двумя разными Foo s:

func sameType<T,U> (a: Foo<T>, b: Foo<U>) -> Bool {
    return false;
}

Компилятор выберет метод, основанный на типе аргумента:

let a = Foo(v: 1.0)
let b = Foo(v: "asdf")
sameType(a, b) // false
sameType(a, a) // true

Это работает аналогично с методами экземпляра в struct:

    func sameType (other: Foo) -> Bool {
        return true
    }

    func sameType<U> (other: Foo<U>) -> Bool {
        return false
    }

Это может иметь неожиданные результаты, если вы смешиваете Swift и Objective-C или должны полагаться на динамический тип по другим причинам:

import Foundation
let x = NSArray(object: 1)
let y = NSArray(object: "string")
sameType(Foo(v: x[0]), Foo(v: y[0])) // true

Результат верен, потому что because Foo(v: x[0]) имеет тип Foo<AnyObject>

Ответ 3

Если я не понял вас неправильно, вы не хотите знать, имеют ли переменные типа FooBar одного типа (потому что они есть), вы хотите проверить, используют ли они один и тот же общий тип.

Так как структура уже содержит свойство универсального типа, вы можете использовать его для сравнения типов, а не с помощью самой структуры:

func areExactType<U>(x: FooBar<U>) -> Bool {
    return x.variable is T
}

Я тестировал на игровой площадке, и он работает с базовыми типами данных, массивами, словарями и т.д. Недостатком является то, что для того, чтобы он работал, структура должна обладать свойством родового типа.