2017-01-26 5 views
2

Вот один,Тонкое предупреждение при использовании SQLite.Swift ... Binding? в любой

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? любому.

enter image description here

И в самом деле, я не знаю, как установить значение по умолчанию, чтобы избежать этого предупреждения, Силе разворачивать значение, чтобы избежать этого предупреждения, или даже Явное приведение к любой с «как любой», чтобы отключите это предупреждение. : O

Вот самодостаточным пример, который воспроизводит такое же предупреждение:

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. 

Относящиеся интересный вопрос:

почему компилятор ...

enter image description here

... кажется, не знает номер строки, с такими проблемами? И действительно: почему предупреждение возникает только после компиляции?

Большинство предупреждений появляются прямо в среде IDE, когда вы печатаете, перед компиляцией.

Это предупреждение, казалось бы (а) быть известны только во время компиляции и (б) компилятор не знает номер строки.

Как это сделать? Какая разница?

+0

Можете ли вы сделать свой код самодостаточным? Существуют несколько методов 'prepare()', поэтому трудно сказать, какой из них вызывается здесь. –

+0

Мартин, спасибо .. (a) Я действительно не знаю, что вы подразумеваете под этим самодостаточным здесь (б), к сожалению, я не могу понять, какой именно вызов heck используется именно в https://github.com /stephencelis/SQLite.swift:/ – Fattie

+0

@ Хамиш: да, хороший момент: я полностью сторонник использования [[Binding?]]. Дело в том, что в противном случае удивительный SQLite.Swift немного задокументирован относительно возможности использования произвольных вызовов sql (это единственный способ использовать его в проекте под рукой); по какой-то причине маленький примерный код, который я нашел в ногу, понравился [[Any]]. В самом деле, я не смог найти никаких оснований для использования [[Any]], поэтому мы действительно изменились на [[Binding?]]. Тем не менее, вопрос, размещенный здесь, держит меня ночью. – Fattie

ответ

5

Вы используете Array «ы sequence initialiser, который имеет подпись:

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

Потому что вы набрали r в [[Any]], Element является [Any]. Однако последовательность, в которой вы проходите, имеет Iterator.Element type of [Binding?]. Следовательно, вы неявно принуждаете Binding? к Any, и согласно SE-0140, это вызовет предупреждение - поскольку вы теряете возможность внутренних элементов, что потенциально нежелательно.

Как говорится в предложении, одним из способов заставить замолчать это предупреждение является добавление явного выражения as Any. В вашем случае, это может быть достигнуто с помощью вложенной map(_:):

r = stmt.map { $0.map { $0 as Any } } 

enter image description here

Это не должно быть более дорогостоящим, чем использование Array «s последовательность Инициализатора из-за того, что прогулка по всем внутренние элементы должны быть выполнены в любом случае из-за различий в том, как Swift сохраняет абстрактно-типизированные значения (см. this Q&A для получения дополнительной информации).

Однако действительно вы должны спросить себя, является ли r должен быть типа [[Any]]. Я не вижу причин, почему вы не должны просто набирать его как [[Binding?]]. Это позволит избавиться от предупреждения и дать вам лучший тип безопасности.

+0

Он работает! Бинго, внутренняя карта. Вы - механик *, чувак. – Fattie

+0

Happy to help @JoeBlow :) – Hamish

+0

послал награду за отличный ответ – Fattie

Смежные вопросы