繁体   English   中英

如何在 Swift 中对结构进行子类化?

[英]How do I subclass a struct in Swift?

struct MyRect : CGRect {...}

是否有可能迅速对结构进行子类化?

我已经在苹果官网上找到了一个例子:这个例子扩展了 CGRect 结构来包含一个计算区域属性:

extension CGRect {
    var area: CGFloat {
        return width * height
    }
}
let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 50.0)
let area = rect.area

如何定义结构的子类?

在 Swift 中无法对struct进行子类化,只能对类进行子类化。 extension不是子类,它只是在现有struct上添加附加功能,这与 Objective-C 中的类别相当。

请在此处查看Apple Swift 文档以了解structclass之间的差异。

你不能在 Swift 中对结构进行子类化,因为这就是 Swift 的设计方式。 一个人可能会争辩说他们不应该这样做并没有内在的原因,但另一个人可能会很容易地争辩说有。 通过禁止它,结构是类的轻量级替代品(在元数据、调度、固定大小等方面是轻量级的)。 如果每个无处不在的数据类型,如整数和字符串(它们是结构)都必须携带额外的包袱(使它们可进行子类化),那么您可以想象与现在相比,该语言可能变得多么不快。

也就是说,在某种意义上,您可以通过创建一个简单地分发您想要子类化的结构的结构来模拟子类化。 例如,如果您想对Calendar进行子类化(您不能这样做,因为它是一个结构),您可以创建一个结构来实例化日历、配置它并返回它。

struct CustomCalendar {
    let american1: Calendar = {
        var c = Calendar(identifier: .gregorian)
        c.timeZone = .current
        c.locale = Locale(identifier: "en_US_POSIX")
        return c
    }()
    
    static let american2: Calendar = {
        var c = Calendar(identifier: .gregorian)
        c.timeZone = .current
        c.locale = Locale(identifier: "en_US_POSIX")
        return c
    }()
    
    static func american3() -> Calendar {
        var c = Calendar(identifier: .gregorian)
        c.timeZone = .current
        c.locale = Locale(identifier: "en_US_POSIX")
        return c
    }
}

let customCal = CustomCalendar()
let cal1 = customCal.american1

let cal2 = CustomCalendar.american2

let cal3 = CustomCalendar.american3()

在这种情况下,您如何出售结构(作为静态属性、通过静态函数、基于实例等)只是个人喜好的问题,因为它们都会为您提供完全相同的东西。

这有点旧,但我遇到了它,并认为我会发布一个在需要时使用的通用模式。 例如,我正在处理的一个应用程序需要使用 AspectRatios 做一些工作。 好吧,在我看来,AspectRatio 只不过是具有一些附加功能的 CGSize。 我想要一个 AspectRatio 和一个 CGSize 之间的一点分离,所以我创建了一个 TypeAlias,然后创建了一个 TypeAlias 的扩展。

像这样的东西:

public typealias AspectRatio = CGSize

public extension AspectRatio {
enum Orientation {
    case landscape
    case portrait
    case square
}
static let square = AspectRatio(width: 1.0, height: 1.0)
static let standard = AspectRatio(width: 4.0, height: 3.0)
static let wideScreen = AspectRatio(width: 16.0, height: 9.0)
static let theater = AspectRatio(width: 21.0, height: 9.0)
static let imax = AspectRatio(width: 1.9, height: 1.0)

func aspectRatio(precision: Int? = nil) -> CGFloat {
    let aspectRatio = width / height

    guard let precision = precision else {
        return aspectRatio
    }

    let multiplier = pow(10, Double(precision))

    let value = (Double(aspectRatio) * multiplier).rounded() / multiplier
    return CGFloat(value)
}

var orientation: Orientation {
    switch self.aspectRatio() {
    case let aspect where aspect > 1.0:
        return .landscape
    case let aspect where aspect < 1.0:
        return .portrait
    default:
        return .square
    }
}

func flipped() -> AspectRatio {
    return AspectRatio(width: height, height: width)
}    
...
}

然后我可以轻松定义这样的变量:

var aspectRatio: AspectRatio = .imax

从 Swift 5.1 开始,现在可以执行类似于您要求的操作:使用组合、 KeyPathdynamicMemberLookup 看看: https : //medium.com/@acecilia/struct-composition-using-keypath-and-dynamicmemberlookup-kind-of-struct-subclassing-but-better-6ce561768612?source=friends_link&sk=da479578032c0b46c1c69114edfb605

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM