简体   繁体   English

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

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

struct MyRect : CGRect {...}

Is it possible at all in swift to subclass a Structure?是否有可能迅速对结构进行子类化?

I have already found out on Apple official website an example: This example extends the CGRect structure to contain a computed area property:我已经在苹果官网上找到了一个例子:这个例子扩展了 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

How can i define a subclass of a structure ?如何定义结构的子类?

It is not possible to subclass a struct in Swift, only classes can be subclassed.在 Swift 中无法对struct进行子类化,只能对类进行子类化。 An extension is not a subclass, it's just adding additional functionality on to the existing struct , this is comparable to a category in Objective-C. extension不是子类,它只是在现有struct上添加附加功能,这与 Objective-C 中的类别相当。

Please see the Apple Swift documentation here to read about the differences between struct and class .请在此处查看Apple Swift 文档以了解structclass之间的差异。

You cannot subclass structures in Swift because that's just how Swift is designed.你不能在 Swift 中对结构进行子类化,因为这就是 Swift 的设计方式。 One could argue there's no inherent reason why they shouldn't be but another could just as easily argue that there is.一个人可能会争辩说他们不应该这样做并没有内在的原因,但另一个人可能会很容易地争辩说有。 By disallowing it, structures are a much more lightweight alternative to classes (lightweight in terms of things like metadata, dispatching, fixed sizing, etc.).通过禁止它,结构是类的轻量级替代品(在元数据、调度、固定大小等方面是轻量级的)。 And if every ubiquitous data type like integer and string (which are structures) had to carry around that extra baggage (to make them subclassable) then you can imagine how less-swift the language may become compared to how it is now.如果每个无处不在的数据类型,如整数和字符串(它们是结构)都必须携带额外的包袱(使它们可进行子类化),那么您可以想象与现在相比,该语言可能变得多么不快。

That said, you can, in some sense, mimic subclassing by creating a structure that simply vends out the structure that you want to subclass.也就是说,在某种意义上,您可以通过创建一个简单地分发您想要子类化的结构的结构来模拟子类化。 For example, if you wanted to subclass Calendar (which you couldn't because it's a structure), you could create a structure that instantiates a calendar, configures it, and returns it.例如,如果您想对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()

How you vend the structures (as a static property, through a static function, instance-based, etc.) is, in this case, just a matter of personal preference because they will all give you the exact same thing.在这种情况下,您如何出售结构(作为静态属性、通过静态函数、基于实例等)只是个人喜好的问题,因为它们都会为您提供完全相同的东西。

This is a bit old, but I ran across it and thought I'd post a common pattern I use when needed.这有点旧,但我遇到了它,并认为我会发布一个在需要时使用的通用模式。 For example, an Application I was working on had the need to do some work with AspectRatios.例如,我正在处理的一个应用程序需要使用 AspectRatios 做一些工作。 Well, in my mind, an AspectRatio is nothing more than a CGSize with some additional functionality.好吧,在我看来,AspectRatio 只不过是具有一些附加功能的 CGSize。 I wanted a little separation between an AspectRatio and a CGSize, so I created a TypeAlias and then created an extension of the TypeAlias.我想要一个 AspectRatio 和一个 CGSize 之间的一点分离,所以我创建了一个 TypeAlias,然后创建了一个 TypeAlias 的扩展。

Something like this:像这样的东西:

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)
}    
...
}

Then I could easily define variables like such:然后我可以轻松定义这样的变量:

var aspectRatio: AspectRatio = .imax

Since Swift 5.1 it is now possible to do something similar to what you asked for: using composition, with KeyPath and dynamicMemberLookup .从 Swift 5.1 开始,现在可以执行类似于您要求的操作:使用组合、 KeyPathdynamicMemberLookup Have a look: https://medium.com/@acecilia/struct-composition-using-keypath-and-dynamicmemberlookup-kind-of-struct-subclassing-but-better-6ce561768612?source=friends_link&sk=da479578032c0b46c1c69111dfb6054e看看: 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