通过比较实例 属性 类型和泛型参数来约束泛型函数
Constraint generic function by comparing instance property type with generic parameter
我想子class ViewControllers 来创建一个通用的协调器class。此协调器 class 应该能够安全地输入类型,将依赖项注入子协调器 classes。子协调员应该只能访问明确定义的依赖项。我用抽象 classes 制作了以下工作操场来布置问题。我对如何解决所描述的问题的其他想法持开放态度。
先决条件
import Foundation
protocol HasFirstDependency {
var first: Any? { get }
}
protocol HasSecondDependency {
var second: Any? { get }
}
typealias AllDependencies = HasFirstDependency & HasSecondDependency
struct AppDependencies: AllDependencies {
var first: Any?
var second: Any?
}
class Coordinator<D> {
var dependencies: D?
}
extension Coordinator {
static func initialize() -> Coordinator<D> {
return Coordinator<D>()
}
}
class ParentCoordinator: Coordinator<AllDependencies> {
var children: [Any] = []
}
class FirstChildCoordinator: Coordinator<HasFirstDependency> {}
class SecondChildCoordinator: Coordinator<HasSecondDependency> {}
问题
以下代码概述了问题(请参阅注释 1. 和 2.)。有没有办法在编译时以上述方式避免强制转换和限制 childType?
extension ParentCoordinator {
func add<C: Coordinator<D>, D>(childType: C.Type) { // 2. ... by setting a constraint like this: "where self.dependecies is D?"
let child = C.initialize()
children.append(child)
if let dependencies: D? = self.dependencies as? D? { // 1. is there any way to avoid this casting ...
child.dependencies = dependencies
} else {
assertionFailure("parentCoordinator does not hold child dependencies")
}
}
}
let parent = ParentCoordinator()
parent.dependencies = AppDependencies(first: "bla", second: "blup")
parent.add(childType: FirstChildCoordinator.self)
let child = parent.children.first as? Coordinator<HasFirstDependency>
print(type(of: parent.dependencies)) // Optional<HasFirstDependency & HasSecondDependency>
print(parent.dependencies?.first) // Optional("bla")
print(parent.dependencies?.second) // Optional("blup")
print(type(of: child?.dependencies)) // Optional<HasFirstDependency>
print(child?.dependencies?.first) // Optional("bla")
//print(child?.dependencies?.second) // does not compile, what I wanted to achieve
我想要的
更具体地说:以下致命错误是我想在编译时捕获的错误。
protocol ForgottenDependency {
var forgotten: Any? { get }
}
class ThirdChildCoordinator: Coordinator<ForgottenDependency> {}
parent.add(childType: ThirdChildCoordinator.self) // Fatal error: parentCoordinator does not hold child dependencies: file MyPlayground.playground, line 49
您要求的是某种符合逻辑的 OR
类型约束:
... where D == HasFirstDependency || HasSecondDependency
swift 中无法分离类型约束。引用 commonly rejected changes:
Disjunctions (logical ORs) in type constraints: These include anonymous union-like types (e.g. (Int | String) for a type that can be inhabited by either an integer or a string). "[This type of constraint is] something that the type system cannot and should not support."
一种可能的解决方案是使依赖项符合通用协议。老实说,这并不能完全解决检测 "forgotten" 依赖项的问题,因为所有的依赖项都必须实现这个通用协议。 .
讨论了这种方法
我想子class ViewControllers 来创建一个通用的协调器class。此协调器 class 应该能够安全地输入类型,将依赖项注入子协调器 classes。子协调员应该只能访问明确定义的依赖项。我用抽象 classes 制作了以下工作操场来布置问题。我对如何解决所描述的问题的其他想法持开放态度。
先决条件
import Foundation
protocol HasFirstDependency {
var first: Any? { get }
}
protocol HasSecondDependency {
var second: Any? { get }
}
typealias AllDependencies = HasFirstDependency & HasSecondDependency
struct AppDependencies: AllDependencies {
var first: Any?
var second: Any?
}
class Coordinator<D> {
var dependencies: D?
}
extension Coordinator {
static func initialize() -> Coordinator<D> {
return Coordinator<D>()
}
}
class ParentCoordinator: Coordinator<AllDependencies> {
var children: [Any] = []
}
class FirstChildCoordinator: Coordinator<HasFirstDependency> {}
class SecondChildCoordinator: Coordinator<HasSecondDependency> {}
问题
以下代码概述了问题(请参阅注释 1. 和 2.)。有没有办法在编译时以上述方式避免强制转换和限制 childType?
extension ParentCoordinator {
func add<C: Coordinator<D>, D>(childType: C.Type) { // 2. ... by setting a constraint like this: "where self.dependecies is D?"
let child = C.initialize()
children.append(child)
if let dependencies: D? = self.dependencies as? D? { // 1. is there any way to avoid this casting ...
child.dependencies = dependencies
} else {
assertionFailure("parentCoordinator does not hold child dependencies")
}
}
}
let parent = ParentCoordinator()
parent.dependencies = AppDependencies(first: "bla", second: "blup")
parent.add(childType: FirstChildCoordinator.self)
let child = parent.children.first as? Coordinator<HasFirstDependency>
print(type(of: parent.dependencies)) // Optional<HasFirstDependency & HasSecondDependency>
print(parent.dependencies?.first) // Optional("bla")
print(parent.dependencies?.second) // Optional("blup")
print(type(of: child?.dependencies)) // Optional<HasFirstDependency>
print(child?.dependencies?.first) // Optional("bla")
//print(child?.dependencies?.second) // does not compile, what I wanted to achieve
我想要的
更具体地说:以下致命错误是我想在编译时捕获的错误。
protocol ForgottenDependency {
var forgotten: Any? { get }
}
class ThirdChildCoordinator: Coordinator<ForgottenDependency> {}
parent.add(childType: ThirdChildCoordinator.self) // Fatal error: parentCoordinator does not hold child dependencies: file MyPlayground.playground, line 49
您要求的是某种符合逻辑的 OR
类型约束:
... where D == HasFirstDependency || HasSecondDependency
swift 中无法分离类型约束。引用 commonly rejected changes:
Disjunctions (logical ORs) in type constraints: These include anonymous union-like types (e.g. (Int | String) for a type that can be inhabited by either an integer or a string). "[This type of constraint is] something that the type system cannot and should not support."
一种可能的解决方案是使依赖项符合通用协议。老实说,这并不能完全解决检测 "forgotten" 依赖项的问题,因为所有的依赖项都必须实现这个通用协议。