【问题标题】:Comparing generic struct types比较通用结构类型
【发布时间】:2015-01-08 18:53:48
【问题描述】:

如何确定一个泛型结构的两个实例是否属于同一类型?

例如,给定以下结构:

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

还有下面的sn-p:

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

如何确定foobarbaz 是相同类型还是不同类型?


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'之间加一个分号)

点类型的预期标识符

预期的表达方式

【问题讨论】:

  • google 搜索后才发现这个问题。未来的我感谢过去的我。

标签: generics swift types struct


【解决方案1】:

编辑:

对不起,过早的回答,它实际上不起作用,因为当从另一个函数中调用时,编译器会选择不同类型的函数:

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

如果您停留在纯 Swift 领域,以下方法将起作用:

给定一个简单的通用结构

struct Foo<T> {
    let v : T
}

您可以定义一个函数sameType,它接受相同类型的Foos,然后只返回true

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

并用两个不同的Foos 重载函数:

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

这与结构上的实例方法的工作方式相同:

    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&lt;AnyObject&gt;

【讨论】:

  • 它在非常有限的情况下工作,否则无用。我可以否决自己的答案吗?
  • 在某些特定情况下仍然有用
  • @Sebastian 我发现您的回答略有改进。
  • 在 Swift 3.0 中似乎不起作用:“参数标签与可用的重载不匹配。”
  • 对我来说,您的回答有点令人困惑。我无法理解哪个部分是正确的,哪个部分是错误的。你知道哪一部分是故意写错的,哪一部分你故意写错是为了指出一个缺陷。可以修改一下吗?
【解决方案2】:

Sebastian's answer 中汲取灵感,我想出了这个解决方案:

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 函数将始终返回truefoobar 的类型,就sameType 而言,是Any,而不是我可能将其向下转换为的任何最具体的类型。


还可能值得注意的是,如果我尝试将其嵌套为实例方法,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")
}

这段代码 sn-p 使 Xcode 崩溃。我不知道为什么……但确实如此……

如果我们改为写:

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

Xcode 编译并运行良好。

【讨论】:

    【解决方案3】:

    如果我没有误解,你不想知道FooBar类型的变量是否属于同一类型(因为它们是),你想检查它们是否使用相同的泛型类型。

    由于结构体已经包含一个泛型类型的属性,你可以使用它来进行类型比较,而不是使用结构体本身:

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

    我在操场上进行了测试,它适用于基本数据类型、数组、字典等。 不利的一面是,为了使其工作,结构必须具有泛型类型的属性。

    【讨论】:

    • 使用结构本身可以适当区分 Foo 和 Foo
    • 是的,我同意这一点,但最终你要寻找的是找出是否T == U。这只是解决问题的另一种方式。我看到您没有将任何答案标记为解决方案,所以我认为您正在寻找替代方案。
    • 但是如果你的结构是多个泛型类型,你的方式很快就会变得复杂。此外,如果类型不是可公开访问的变量怎么办?
    • 答案基于您提供的示例代码 - 它不是通用的,我同意当泛型不止一个时它会变得复杂。至于可访问性,私有变量是可访问的,只要x 参数属于同一类型(在我们的情况下始终如此)
    猜你喜欢
    • 2011-08-31
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多