Swift 泛型:类型声明中的 where
Swift Generics: where in type declaration
我正在尝试制作一个 API 允许调用者将 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
本身的原因是,从块内,调用者不需要将参数转换为它的原始类型
所以,我的问题是:在声明变量类型时有没有办法使用 where
子句?
我可以看到实现此目的的多种方法。使用哪一个取决于您,具体取决于您希望如何组织代码。
使 SomeClass
本身通用:
class SomeClass<V: UIView> {
var data: SomeStruct<V>?
...
}
使 SomeStruct 符合仅公开 UIView 的协议(具有 no 关联类型),因此您仍然可以编写计算属性:
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)
}
}
而不是结构,使用非泛型 class 的泛型子 class(这与 #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)
}
}
你根本不需要 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)
我正在尝试制作一个 API 允许调用者将 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
本身的原因是,从块内,调用者不需要将参数转换为它的原始类型
所以,我的问题是:在声明变量类型时有没有办法使用 where
子句?
我可以看到实现此目的的多种方法。使用哪一个取决于您,具体取决于您希望如何组织代码。
使
SomeClass
本身通用:class SomeClass<V: UIView> { var data: SomeStruct<V>? ... }
使 SomeStruct 符合仅公开 UIView 的协议(具有 no 关联类型),因此您仍然可以编写计算属性:
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) } }
而不是结构,使用非泛型 class 的泛型子 class(这与 #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) } }
你根本不需要 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)