Swift:将Foo<String>转换为Foo<Any>

4

这是我的代码

class Foo<T> {

}

class Main {
    static func test() {
        var foo: Foo<Any>

        var bar = Foo<String>()
        //Do all my stuff with foo necessitating String

        foo = bar
    }
}

当我尝试将foo = bar赋值时,出现错误无法将类型为Foo<String>的值分配给类型为Foo<Any>的值。 我不明白为什么会出现这个错误,因为String符合Any。 如果我使用Array完全相同的方法,就不会有任何错误。
static func test() {
        var foo: Array<Any>

        var bar = Array<String>()
        //Do all my stuff with foo necessitating String

        foo = bar
    }

有人知道我的代码出了什么问题吗?谢谢


尝试使用 AnyObject 而不是 Any。 - Basheer_CAD
不行,同样的问题,而且String类型不符合AnyObject。 - Jaeger
@Jaeger,你使用这个的场景是什么?我只是好奇,因为我正在尝试解决这个问题。 - Will M.
2个回答

2

数组和字典是具有此类行为的特殊类型。然而,这不适用于自定义泛型类型。类型Foo<Any>不是Foo<String>的超类型(或在此情况下是超类),即使AnyString的超类型。因此,您不能将这些类型的变量分配给彼此。

根据您的特定情况,Swift Cast Generics Type中概述的解决方案可能适用于您。当Foo包装类型为T的值时,您可以添加一个通用构造函数,将来自不同类型实例的Foo中的值转换。

class Foo<T> {
    var val: T

    init(val: T) {
        self.val = val
    }

    init<O>(other: Foo<O>) {
        self.val = other.val as! T
    }
}

class Main {
    static func test() {
        var foo: Foo<Any>

        var bar = Foo<String>(val: "abc")
        //Do all my stuff with foo necessitating String

        foo = Foo<Any>(other: bar)
    }
}

数组和字典的“特殊性”是如何声明的?谢谢。 - Darko
为什么foo.val.dynamicType打印的是Swift.String而不是Swift.Any? - Will M.
@Darko 抱歉,我不知道那个。这是 Swift 的内部机制。我认为主要的区别在于数组和字典不是类而是结构体,并且可能会受到编译器的特殊处理。 - hennes
@WillM。这是一个有趣的发现。实际上,var x: Any = "abc"; print(x.dynamicType) 打印出 Swift.String,而 var x: AnyObject = "abc"; print(x.dynamicType) 则打印出 Swift._NSContiguousString。我猜 Any 类型只是作为底层实际类型的盲目代理。 - hennes
@hennes,我对你的答案进行了一些改进,使其更加强大和安全。 - Will M.
@WillM. 这是一个很棒的改进! :) - hennes

2

我在@hennes的答案基础上进行了改进,增加了定义从类型O转换为类型T的能力。

class Foo<T> {
    var val: T

    init(val: T) {
        self.val = val
    }

    init<O>(other:Foo<O>, conversion:(O) -> T) {
        self.val = conversion(other.val)
    }
}

class Main {
    static func test() {
        var foo: Foo<Int>

        var bar = Foo<String>(val: "10")
        //Do all my stuff with foo necessitating String

        foo = Foo<Int>(other: bar, conversion: {(val) in
            return Int(val.toInt()!)
        })
        print(foo.val) //prints 10
        print(foo.val.dynamicType) //prints Swift.Int
    }
}

这使您能够在两种不支持彼此强制转换的类型之间进行转换。此外,它会在转换非法时发出编译器警告,而不是由于强制转换而导致崩溃。

不知道为什么1行或>1行闭包的编译器警告有所不同,但确实存在。

1行闭包的编译器警告不好 useless compiler warning

2行闭包的编译器警告很好 enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接