简体   繁体   English

Swift泛型:类型声明中的位置

[英]Swift Generics: where in type declaration

I'm trying to make an API that allows a caller to pass a subclass of UIView and a block to a function, and later the receiver will call that block with the given UIView subclass instance and another argument. 我正在尝试制作一个允许调用者将UIView的子类和一个块传递给函数的API,然后接收者将使用给定的UIView子类实例和另一个参数来调用该块。 I've broken down the issue so that it runs in a playground: 我已经解决了这个问题,使其可以在操场上运行:

import UIKit

struct SomeStruct<T where T: UIView> {

    let view: T
    let block: ((T, Int) -> Void)

    //some computed variables here that rely on T being a UIView
}

class SomeClass {

    var data: SomeStruct<UIView>? //Ideally, SomeStruct<? where ? : UIView>

    func doSomethingLater<V where V: UIView>(view: V, block: ((V, Int) -> Void)) {

        //Cannot convert value of type '(V, Int) -> Void' to expected argument type '(_, Int) -> Void'
        self.data = SomeStruct(view: view, block: block)
    }
}


The caller would then use SomeClass like this: 然后,调用者将使用SomeClass像这样:

let c = SomeClass()

let label = UILabel()
c.doSomethingLater(b) { (label, idx) in
    //l is type UILabel
}   

let button = UIButton(type: .Custom)
c.doSomethingLater(b) { (button, idx) in
    //b is type UIButton
} 

My reasoning behind wanting to restrict to subclasses of UIView rather than a UIView itself is so that from within the block, the caller does not need to cast the argument to it's original type 我想限制于UIView子类而不是UIView本身的原因是,这样,从块内部,调用者无需将参数强制转换为其原始类型。

So, my question is: is there a way to use the where clause when declaring a variable's type? 所以,我的问题是:在声明变量的类型时,是否可以使用where子句?

I can see multiple ways of achieving this. 我可以看到实现这一目标的多种方法。 Which one to use is up to you, depending how you want your code to be organized. 使用哪种代码取决于您,具体取决于您希望如何组织代码。

  1. Make SomeClass itself generic: 使SomeClass本身通用:

     class SomeClass<V: UIView> { var data: SomeStruct<V>? ... } 
  2. Make SomeStruct conform to a protocol (with no associated type) which exposes only a UIView, so you can still write the computed properties: 使SomeStruct符合仅暴露UIView的协议( 关联类型),因此您仍然可以编写计算出的属性:

     protocol SomeStructType { var view: UIView { get } } extension SomeStructType { // add computed properties based on self.view... } struct ConcreteStruct<V: UIView>: SomeStructType { let realView: V let block: (T, Int) -> Void var view: UIView { return realView } // satisfy the protocol } class SomeClass { var data: SomeStructType? ... func doSomethingLater<V: UIView>(view: V, block: (V, Int) -> Void) { data = ConcreteStruct(realView: view, block: block) } } 
  3. Rather than a struct, use a generic subclass of a non-generic class (this is very similar to #2) 而非结构,请使用非泛型类的泛型子类(这与#2非常相似)

     class SomeData { var view: UIView { fatalError("abstract method") } ... } class ConcreteData<V: UIView>: SomeData { let realView: V let block: (V, Int) -> Void override var view: UIView { return realView } // override the getter init(view: V, block: (V, Int) -> Void) { ... } } class SomeClass { var data: SomeData? ... func doSomethingLater<V: UIView>(view: V, block: (V, Int) -> Void) { data = ConcreteData(realView: view, block: block) } } 

you don't need SomeClass at all 你根本不需要SomeClass

struct S<T> {
    let a: T
    let b: (T, Int) -> Void
}

let s = S(a: "a") { (i, j) in
    // see, that a is NOT accessible here!!!!
    print("1:",i,j)
}

s.b("b", 1) // compiler take care about types, so (String,Int) is the only option

// to be able change b later !!!!!
struct S1<T> {
    let a: T
    var b: (T, Int) -> Void
}

var s1 = S1(a: 100) { _ in }
s1.b = { label, index in
    print("2:",s1, label, index)
}

s1.b(200,2)

class C {
    var i: Int = 0
}
let c:C? = C()
var s2 = S1(a: c) { _ in } // so later i can modify c
s2.b = { label, index in
    s2.a?.i = index
}
print("3:",c, c?.i)
s2.b(nil, 100)
print("4:",c, c?.i)

it prints 它打印

 1: b 1
 2: S1<Int>(a: 100, b: (Function)) 200 2
 3: Optional(C) Optional(0)
 4: Optional(C) Optional(100)

or 要么

let c2 = C()
c2.i = 200

// modify c.i to max of c2.i and some value
s2.b = { c, i in
    if let j = c?.i {
        s2.a?.i = max(j,i)
    }
}

s2.b(c2, 50) // s2 still modify c
print("5:",c, c?.i)

s2.b(c2, 250) // s2 still modify c
print("6:",c, c?.i)

prints 版画

5: Optional(C) Optional(200)
6: Optional(C) Optional(250)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM