【问题标题】:Extended capability for a more restrictive generic更严格的泛型的扩展功能
【发布时间】:2020-08-30 05:33:23
【问题描述】:

我有一个基于 Comparable 的通用二叉搜索树:

public class BSTree<T: Comparable> {
    public func insert(_ val: T, _ n: Int) {
        // ...
    }

    @discardableResult
    public func delete(_ val: T, _ n: Int) -> Int {
        // ...
    }
}

如果 T 是算术类型,我想添加提供值总和的功能。我尝试了以下方法:

public class BSTree<T: Comparable> {
    private var sumStorage: T?

    public func insert(_ val: T, _ n: Int) {
        if let arithVal = val as? AdditiveArithmetic {
            for _ in 0 ..< n { sumStorage += arithVal }
        }
        // ...
    }

    @discardableResult
    public func delete(_ val: T, _ n: Int) -> Int {
        // ...
        numDeleted = ...
        if let arithVal = val as? AdditiveArithmetic {
            for _ in 0 ..< numDeleted { sumStorage -= arithVal }
       }        
    }
}

extension BSTree where T: AdditiveArithmetic {
    public var sum: T {
        sumStorage as? T ?? T.zero
    }
}

当然,当我尝试将val 转换为AdditiveArithmetic 时,我得到“协议'AdditiveArithmetic' 只能用作通用约束,因为它具有Self 或关联的类型要求”。加上sumStorage 不是AdditiveArithmetic,所以我不能添加它,我不能让它成为扩展的存储属性,因为......你不能。

我最后想到的是使用继承:

class SummedBSTree<T>: BSTree<T> where T: AdditiveArithmetic & Comparable {

    public var sum = T.zero

    override public func insert(_ val: T, _ n: Int) {
        super.insert(val, n)
        for _ in 0 ..< n { sum += val }
    }

    @discardableResult
    override public func delete(_ val: T, _ n: Int) -> Int {
        let numDeleted = super.delete(val, n)
        for _ in 0 ..< numDeleted { sum -= val }
        return numDeleted
    }

}

这行得通,但它似乎是使用大锤的情况,珠宝商的螺丝刀应该能够做到这一点。令人沮丧的是,在 Objective-C(和其他强类型语言)中很容易做到的事情在 Swift 中却如此困难。有人可以想出一种无需子类化即可添加求和功能的方法吗?

【问题讨论】:

  • 向 BSTree 添加关联类型是否有效?

标签: swift generics inheritance swift-extensions


【解决方案1】:
import UIKit
//https://stackoverflow.com/questions/61784548/swift-extended-capability-for-a-more-restrictive-generic

protocol ON1Speedable {
    
    associatedtype Item: Comparable

    var sumStorage: Item? { get set }
    
}

public class BSTree<T: Comparable> {
        
    var sumStorage: T?
    
    init(sumStorage: T? = nil) {
        self.sumStorage = sumStorage
    }
    
}

extension ON1Speedable where Item: AdditiveArithmetic, Item: Strideable, Item.Stride: SignedInteger {
    
    mutating func insert(_ val: Item, _ n: Int) {
        sumStorage = sumStorage ?? Item.zero
        for _ in 0..<n { sumStorage! += val }
    }
    
    @discardableResult
    mutating func delete(_ val: Item, _ n: Int) -> Item? {
        sumStorage = sumStorage ?? Item.zero
        for _ in Item.zero..<val { sumStorage! -= val }
        
        return sumStorage
    }
    
}

extension BSTree: ON1Speedable { }

var g2 = BSTree<Int>(sumStorage: 0)

g2.sumStorage
g2.insert(5, 5)
g2.sumStorage // 25
g2.delete(5, 5) // 0

var g3 = BSTree<String>()

g3.sumStorage // nil
//g3.insert("foo", 5) // Error: Referencing instance method 'insert' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'
g3.sumStorage // nil
//g3.delete("bar", 5) // Error: Referencing instance method 'delete' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'

【讨论】:

  • 是的,谢谢,这确实给出了总和,但我试图在修改树时保持总和,以便可以随时以 O(1) 复杂度查询它。
  • 明白了。我更新了代码。这会让你更亲近吗?我很乐意解释任何不透明的事情。
  • 是的,谢谢,这可能会奏效。我会尝试根据我的代码调整它。
猜你喜欢
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
相关资源
最近更新 更多