【问题标题】:Lazy initialisation of individual array elements单个数组元素的延迟初始化
【发布时间】:2017-12-09 18:59:05
【问题描述】:

在 Swift 中,lazy properties 允许我们仅在请求时初始化一个类成员,而不是直接在运行时初始化 - 这对于计算量大的操作很有用。

我在 Swift 4 中有一个类,负责从提供的 StrategyProtocol 对象的编译时(开发人员硬编码)数组初始化 strategy。它看起来像这样:

class StrategyFactory {
    private var availableStrategies: [StrategyProtocol] = [
        OneClassThatImplementsStrategyProtocol(),
        AnotherThatImplementsStrategyProtocol() // etc
    ]

    public func createStrategy(): StrategyProtocol {
        // Depending on some runtime-calculated operation
        // How do I do this nicely here?
    }
}

但是,据我了解,将 () 放在每个策略的末尾会初始化对象(?),而我可能只想根据某些运行时条件创建一个。

无论哪种方式,是否可以在 Array 类成员中的值周围放置 lazy 以仅在我要求时实例化我想要的那个?还是我必须使用闭包或其他替代方法来解决这个问题?


当前尝试

这是在做我认为的事情吗?在我得到数组的第一个元素并执行它之前,它实际上不会实例化策略?

private var availableStrategies: [() -> (StrategyProtocol)] = [
    { OneClassThatImplementsStrategyProtocol() }
]

【问题讨论】:

标签: arrays swift lazy-initialization


【解决方案1】:

您的“当前尝试”按照您的想法进行。你有一个数组 闭包,并且策略仅在闭包被初始化时 执行。

一种可能的替代方法:存储一个 types 数组,而不是 实例或闭包(如Zalman Stern also suggested)。

为了按需创建实例,一个 init() 要求必须添加到协议中(然后必须 由required init() 满足,除非类是final, 比较Why use required Initializers in Swift classes?)。

一个可能的优势是您可以查询静态属性 以便找到合适的策略。

这是一个独立的小例子,其中createStrategy() 创建并返回第一个“绝妙”策略:

protocol StrategyProtocol {
    init()
    static var isFantastic: Bool { get }
}

class OneClassThatImplementsStrategyProtocol : StrategyProtocol {
    required init() { }
    static var isFantastic: Bool { return false }
}

final class AnotherThatImplementsStrategyProtocol : StrategyProtocol {
    init() { }
    static var isFantastic: Bool { return true }
}

class StrategyFactory {
    private var availableStrategies: [StrategyProtocol.Type] = [
        OneClassThatImplementsStrategyProtocol.self,
        AnotherThatImplementsStrategyProtocol.self // etc
    ]

    public func createStrategy() -> StrategyProtocol? {
        for strategy in availableStrategies {
            if strategy.isFantastic {
                return strategy.init()
            }
        }
        return nil
    }
}

【讨论】:

  • "does what you think it does" OP 可能不清楚数组元素没有替换闭包,这就是他在谈到惰性属性时所期待的。
  • @JoshCaswell:这不是我的印象(来自“直到我得到数组的第一个元素并执行它,它实际上不会实例化策略?”) – 也许 OP 可以对此发表评论,如有必要,我会澄清。
  • 我没想到闭包的结果会取代闭包。感谢你的回答!我最终选择了关闭路线,因为我并不热衷于在任何对我的 API 选择没有直接要求的地方添加 inits。不过,我使用了Types,这似乎是一种很好的方法,所以我将其标记为正确。
【解决方案2】:

ANYCLASS, META TYPE AND .SELF 可能会回答您的问题。 (我不是 Swift 方面的专家,但元类的使用可能是你想要的,而且正如我所料,Swift 似乎支持它们。)你可以查看这个 Stack Overflow search

编辑:如果不清楚,想法是让策略数组包含协议的元类而不是实例化。尽管这取决于您是否需要为具有惰性属性的类的每个实例化一个新的策略对象,或者策略是否有效地是全局的并创建了缓存的策略。如果是后者,那么保存它们的惰性数组方法可能会更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-05
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多