Swift Generics:在类型声明中的位置

时间:2016-04-05 06:05:30

标签: swift generics where

我正在尝试创建一个API,允许调用者将void rotateClockwise( int degree ) { int currentDegree = getDegree(); int desiredDegree = currentDegree + degree; if( desiredDegree > 359 ) { desiredDegree -= 359; } do { newDegree = getDegree(); // Returns current degree desiredDegreeSINE = sin(desiredDegree * (PI/180)); currentDegreeSINE = sin(newDegree * (PI/180)); if( desiredDegreeSINE > 0 && currentDegreeSINE < 0 ) { newDegree = newDegree - 360; } if( newDegree >= desiredDegree ) { // Stop rotating break; } else { // Keep rotating } } while(true); } 的子类和一个块传递给一个函数,然后接收器将使用给定的UIView子类实例调用该块和另一个论点。我已经解决了这个问题,所以它在游乐场里运行:

UIView


然后呼叫者将使用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) } } ,如下所示:

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 } 而不是UIView本身的子类的原因是,在块内,调用者不需要将参数强制转换为它的原始类型

所以,我的问题是:在声明变量的类型时,有没有办法使用UIView子句?

2 个答案:

答案 0 :(得分:1)

我可以看到实现这一目标的多种方法。使用哪一个取决于您,具体取决于您希望如何组织代码。

  1. SomeClass本身通用:

    class SomeClass<V: UIView> {
        var data: SomeStruct<V>?
        ...
    }
    
  2. 使SomeStruct符合协议(使用 no 关联类型),该协议仅公开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. 而不是结构,使用非泛型类的泛型子类(这与#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)
        }
    }
    

答案 1 :(得分:-2)

你根本不需要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)

打印

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

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)

打印

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