计算属性:get 和 set 之间的不同类型

Posted

技术标签:

【中文标题】计算属性:get 和 set 之间的不同类型【英文标题】:Computed property: different types between get and set 【发布时间】:2017-04-27 07:31:54 【问题描述】:

我想将浮点数范围映射到字符串。具体来说,我想转换风的度数方向,例如,在具有基本方向的相应字符串中:220 -> SW

可以使用自定义get 声明创建声明为Float 类型的计算属性,以返回相应的String?这样我会写成Float,但我会读成String

类似:

var windDirection: Float? 
    get 
        switch self.windDirection 
        case 348.75..<11.25:
            return "N"
            break
        ...
        default:
            break
        
    
    set (newValue) 
        self.windDirection = newValue
    

如果不是,我有什么可能产生相同的行为?

【问题讨论】:

我也很想看到答案,但老实说,我希望答案是响亮的“不”:-) 答案不,你实际上需要ValueTransformer 【参考方案1】:

据我所知,这是不可能的。 计算属性仍然是只能是单一类型的属性。

也就是说,也许你最好有自己的类型:

struct WindDirection 
    var degrees: Float
    var stringValue: String 
        get 
            // compute the correct string here
            return "\(degrees)"
        
        set 
            // compute the correct float value here
            degrees = Float(newValue) ?? 0
        

    


var windDirection: WindDirection

如果您不想使用自己的类型,则必须坚持使用 2 个不同的属性。

【讨论】:

这是处理这种情况的更好方法。 顺便说一句:遵守CustomStringConvertible 并将stringValue 重命名为description 将获得更多好处。【参考方案2】:

我想也许你可以像这样使用枚举

enum Wind 
    case degree(Float)
    case direction(String)


extension Wind 

    init?(degree: Float) 
        switch degree 
        case 11.25..<385:
            self = .direction("N")
        default:
            return nil
        
    



let wind = Wind(degree: 100) // Result is direction("N")

【讨论】:

请注意,与11.25..&lt;385 的模式匹配将为[11.25, 385.0) 范围内的任何值产生N(北),即180,这是南:) 是的,我没注意到【参考方案3】:

不要这样做!不要这样做!!永远不要这样做。我无法用言语来解释这是多么糟糕的想法。

private var _windDirection: Float?

var windDirection: Any? 
    get 
        guard let windDirection = _windDirection else 
            return nil
        

        switch windDirection 
        case 348.75..<11.25:
            return "N"
        ...
        default:
            return nil
        
    
    set (newValue) 
        guard let windDirection = newValue as? Float else 
            _windDirection = nil
            return
        

        _windDirection = windDirection
    

【讨论】:

【参考方案4】:

(您应该看看与CustomStringConvertible 的一致性,但对于技术讨论,以下...)

可以,但是实现一个enum 包装器,其中每个案例包装不同类型的关联值(很像Optional&lt;Int&gt; 包装.none.some(Int))。

enum WindDirection 
    case asDegree(Float)
    case asString(String)

这样,您可以让您的实例变量windDirection 成为两种不同包装类型的包装器,这将允许您在setter 中期望一种包装类型并在getter 中返回另一种包装类型。例如:

class Foo 
    private var _windDirection: WindDirection
    var windDirection: WindDirection 
        get 
            switch _windDirection 
            case .asDegree(let angle):
                switch(angle) 
                case 348.75..<360.0, 0..<11.25: return .asString("N")
                case 11.25..<33.75: return .asString("NE")
                /* ... */
                case _ : return .asString("Not expected")
                
            case _ : return .asString("Not expected")
            
        
        set (newValue) 
            if case .asDegree(_) = newValue 
                _windDirection = newValue
            
        
    

    init?(_ windDirection: WindDirection) 
        guard case .asDegree(_) = windDirection else  return nil 
        _windDirection = windDirection
    

示例用法(但是,您需要在调用实例属性时处理包装的关联值的展开)

// attempt initialization
if let foo = Foo(.asDegree(11.0)) 

    // getter
    if case .asString(let windDirection) = foo.windDirection 
        print(windDirection) // N
    

    // setter
    foo.windDirection = .asDegree(15.75)

    // getter
    if case .asString(let windDirection) = foo.windDirection 
        print(windDirection) // NE
    

【讨论】:

以上是关于计算属性:get 和 set 之间的不同类型的主要内容,如果未能解决你的问题,请参考以下文章

计算属性(get和set)

Swift get和set方法以及只读属性(计算型属性,本身不保存数据,都是通过计算获得结果)

vue计算属性进入页面就调用怎么设置

Ember.js、set() 和计算属性

C#面向对象基础2

计算属性computed和watch侦听器