2017-02-17 5 views
0

奇妙な一般的な振る舞いを見て、私が私の理解の中で何かを見逃していると信じさせる。Swift:実行時の一般的な型推論

次のメソッドを使用して、JSON応答をループしてジェネリックメソッドを呼び出します。 UserCardEcardすべてが順番に

let props:[(label:String, type:IDObject.Type)] = [ 
    (label: "deletedUsers", type: User.self), 
    (label: "deletedCards", type: Card.self), 
    (label: "deletedECards", type: Ecard.self) 
] 

for prop in props { 
    if let ids = json[prop.label].arrayObject as? [Int], ids.count > 0 { 
     DataManager.shared.delete(prop.type, ids: ids) 
    } 
} 

func delete<T:IDObject>(_ type:T.Type, ids:[Int]) { 
    guard ids.count > 0 else { return } 
    if let objectsToDelete = objects(type, where: NSPredicate(format: "identifier IN %@", ids)) { 
     delete(objectsToDelete) 
    } 
} 

func delete<T:Object>(_ objects:Results<T>) { 
    guard objects.count > 0 else { return } 
    do { 
     let realm = try Realm() 
     try realm.write { 
      realm.delete(objects) 
     } 
    } catch { 
     print(error) 
    } 
} 

delete(_ type:T.Type, ids:[Int])機能は、ジェネリック型をこのように推測することはできませんObject(レルムクラス)から継承され、IDObjectから継承します。

ただし、for prop in propsループをアンラッピングすると、正常に動作します。

if let userIds = json["deletedUsers"].arrayObject as? [Int], userIds.count > 0 { 
    DataManager.shared.delete(User.self, ids: userIds) 
} 

ジェネリックはコンパイル時にのみ動作しますか、実行時にこれを動的に処理する方法はありますか?

+0

あなたが*」によって、正確に何を意味します ' delete関数はこのようにジェネリック型を推論することはできません* "?コンパイラエラーが発生しますか? (もしそうなら、どこですか?) 'DataManager.shared.delete(prop.type、ids:ids')の閉じ括弧がありません。一つのパラメータで' delete'をオーバーロードしない限り、あなたはそれを呼び出すことができません – Hamish

+0

@Hamishコードベース全体が非常に大きく、私はそれを共有する自由がありません。(例えば、 "delete(objectsToDelete)") delete(:)メソッドは 'Results ' - 'IDObject'が' Object'を継承していることを期待しています。私が見ている動作はdelete(objects :)メソッド、objects.count == 0にあります。 – dmorrow

+0

コードベース全体を共有する必要はありません - 同じ問題を再現する最小限の自己完結型の例のみです。 DataManager.shared.delete'は 'delete(_:ids:)'を参照することになっていますか? 'objects(_:where:)'は何を返しますか(あなたは関数を表示しなくても、同じ問題を再現する関数を模擬してください)。 'ids'は問題と関連していますか? (そうでない場合は、取り外してください)。 – Hamish

答えて

1

ジェネリックはコンパイル時に評価され、単一の具体的な型が割り当てられます。実行時に型推論などはありません。

私はあなたがしたい主な変更があると思う:

func delete(_ type:IDObject.Type, ids:[Int]) { 

あなたはtypeにこの機能を特化したくない、あなただけのtypeを通過したいです。

objects(_:where:)が返すものは明確ではないため、deleteメソッドが破損する可能性があります。あなたはそれがあまり具体的にする必要がある場合があります。

func delete(_ objects:Results<Object>) { 

(これはサブタイピングのための万能薬ではありません。私はobjects(_:where:)戻っ正確Results<Object>と仮定しています。)

+0

* *「実行時の型推論」によって、彼は[this](http://stackoverflow.com/a/30945263/5175709)のようなものを意味します。**プロトコルは静的または動的ディスパッチを選択できます。**彼は基本的には静的対動的ディスパッチ。 – Honey

+0

私はここで何か不足しているかもしれませんが、 'type'パラメータの静的な型を変更するとOPのコードの実行時の振る舞いが変わることはありません(' delete'を呼び出すときを考えてください。(実際に 'DataManager.shared .delete')、 'T'はすでに' IDObject'と推測されています)。ジェネリックはコンパイラの最適化としてのみ特化されていることにも注意してください。 – Hamish

+0

これはすでに 'IDObject'と推定されているかもしれませんが、読者がより多くのことが起こっていると思われるので、それを専門とするのが最も紛らわしいです(このコードはコンパイルされないためテストするのが難しい)。 「特殊化」とは、関数の一意のバージョンがコンパイラによって書き込まれることを意味するものではありません。 'Array 'は、コンパイラによってどのように実装されているかにかかわらず、 'Int'に対する' Array'の特殊化です。 –

関連する問題