使用 SQLite.Swift 时的细微投射警告 ... 绑定?去任何

Subtle cast warning when using SQLite.Swift ... Binding? to Any

这是一个,

 import SQLite

    var r:[[Any]] = []

    do {
        if let stmt = try local.db?.prepare(q) {
            r = Array(stmt)
        }
        else {
            print("woe in sql?")
        }
    }
    catch { return [] }

来电

 r = Array(stmt)

给出从 'Binding?' 隐式强制转换为 Any 的 表达式。

事实上,我不知道如何提供一个默认值来避免这个警告,Force-unwrap这个值来避免这个警告,或者甚至用 'as Any' 显式地转换成 Any 来消除这个警告。 :O

这是一个重现相同警告的 self-contained 示例:

struct Binding {}

struct Statement : IteratorProtocol, Sequence {
    func next() -> [Binding?]? {
        return nil
    }
}

let stmt = Statement()

let r: [[Any]]

r = Array(stmt) // warning: Expression implicitly coerced from 'Binding?' to Any.

相关有趣问题:

为什么编译器...

...好像不知道行号,有这样的问题?确实:为什么警告只在编译后出现?

编译前,大多数警告会在您输入时出现在 IDE 中。

这个警告似乎 (a) 只有在编译期间才知道,而 (b) 编译器不知道该行数.

怎么会这样?有什么区别?

您正在使用 Arraysequence initialiser,其签名为:

init<S>(_ s: S) where S : Sequence, Element == S.Iterator.Element

因为您输入 r[[Any]]Element[Any]。但是,您传入的序列有一个 Iterator.Element type of [Binding?]. Therefore, you're implicitly coercing Binding? to Any, and as per SE-0140,这将引发警告 – 因为您正在失去内部元素的可选性,这可能是不受欢迎的。

如提案所述,消除此警告的一种方法是添加显式 as Any 转换。在您的情况下,这可以通过使用嵌套的 map(_:):

来实现
r = stmt.map { [=11=].map { [=11=] as Any } }

这应该不会比使用 Array 的序列初始化器更昂贵,因为在任何一种情况下都必须遍历所有内部元素,这是由于Swift 如何存储 abstract-typed 值(有关详细信息,请参阅 )。

然而,真的你应该问问自己 r 是否应该是 [[Any]] 类型。我看不出为什么你不应该将其键入 [[Binding?]]。这样做既可以消除警告,又可以给你更好的 type-safety.