如何在switch语句之外访问Swift枚举关联值

ver*_*rec 48 enums swift

考虑:

enum Line {
    case    Horizontal(CGFloat)
    case    Vertical(CGFloat)
}

let leftEdge             =  Line.Horizontal(0.0)
let leftMaskRightEdge    =  Line.Horizontal(0.05)
Run Code Online (Sandbox Code Playgroud)

如何在lefEdge不使用switch语句的情况下直接访问相关值?

let noIdeaHowTo          = leftEdge.associatedValue + 0.5
Run Code Online (Sandbox Code Playgroud)

这甚至没有编译!

我看了一下这些 SO 问题,但没有一个答案似乎解决这个问题.

noIdeaHowTo上面的非编译行应该是单行,但由于associated value可以是任何类型,我甚至无法看到用户代码如何在le enum本身中编写"泛型"get或associatedValue方法.

我最终得到了这个,但它很严重,每次我添加/修改案例时都需要我重新访问代码...

enum Line {
    case    Horizontal(CGFloat)
    case    Vertical(CGFloat)

    var associatedValue: CGFloat {
        get {
            switch self {
                case    .Horizontal(let value): return value
                case    .Vertical(let value): return value
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有人指点吗?

ver*_*rec 69

正如其他人所指出的,现在Swift 2中有可能实现这一点:

import CoreGraphics

enum Line {
    case    Horizontal(CGFloat)
    case    Vertical(CGFloat)
}

let min = Line.Horizontal(0.0)
let mid = Line.Horizontal(0.5)
let max = Line.Horizontal(1.0)

func doToLine(line: Line) -> CGFloat? {
    if case .Horizontal(let value) = line {
        return value
    }
    return .None
}

doToLine(min) // prints 0
doToLine(mid) // prints 0.5
doToLine(max) // prints 1
Run Code Online (Sandbox Code Playgroud)

  • 你会如何以任何枚举和任何情况的方式实现它? (2认同)
  • @RodrigoRuiz 我为您推荐 Arkku 的答案。您需要一个包含枚举和值的结构,而不仅仅是一个枚举。 (2认同)

小智 9

您可以使用保护语句来访问关联的值,如下所示。

enum Line {
    case    Horizontal(Float)
    case    Vertical(Float)
}

let leftEdge             =  Line.Horizontal(0.0)
let leftMaskRightEdge    =  Line.Horizontal(0.05)

guard case .Horizontal(let leftEdgeValue) = leftEdge else { fatalError() }

print(leftEdgeValue)
Run Code Online (Sandbox Code Playgroud)


ste*_*vex 9

您可以使用 if case let 语法在不使用开关的情况下获取关联值:

enum Messages {
    case ping
    case say(message: String)
}

let val = Messages.say(message: "Hello")

if case let .say(msg) = val {
    print(msg)
}
Run Code Online (Sandbox Code Playgroud)

如果枚举值为 .say,则 if case let 内的块将运行,并且范围内的关联值将作为您在 if 语句中使用的变量名。


Ark*_*kku 8

我想你可能会尝试使用enum它不适合的东西.访问相关值的方法确实是通过switch你已经完成的,这个想法是switch总是处理每个可能的成员情况enum.

不同成员enum可以有不同的相关值(例如,你可以有Diagonal(CGFloat, CGFloat)Text(String)enum Line),所以你必须确认你正在处理,然后才能访问相关值的情况.例如,考虑:

enum Line {
    case Horizontal(CGFloat)
    case Vertical(CGFloat)
    case Diagonal(CGFloat, CGFloat)
    case Text(String)
}
var myLine = someFunctionReturningEnumLine()
let value = myLine.associatedValue // <- type?
Run Code Online (Sandbox Code Playgroud)

你怎么能冒昧地得到相应的数值myLine时,有可能与你打交道CGFloat,String或者2个 CGFloat S' 这就是为什么你需要switch首先发现case你拥有的.

在您的特定情况下,它听起来就像你可能是一个更好的关闭classstruct进行Line,那么这可能会存储CGFloat,也有一个enum财产VerticalHorizontal.或者您可以建模VerticalHorizontal作为单独的类,Line作为协议(例如).

  • 是的。我绝对认为这需要语言支持。在这种情况下,返回值不应只涉及不同的类型,而且还应涉及不同的数量。可能是一个变化的计数元组,如 case x ... return (1) case y ... return (0, "stuff") case z ... return (-1, 3.14, ["for", "good" , “措施”])。这可能最好留给编译器直接支持。闻到雷达的味道...... (2认同)

Dev*_*ist 5

为什么这是不可能的已经回答了,所以这只是一个建议。你为什么不这样实现它。我的意思是枚举和结构都是值类型。

enum Orientation {
    case Horizontal
    case Vertical
}

struct Line {

    let orientation : Orientation
    let value : CGFloat

    init(_ orientation: Orientation, _ value: CGFloat) {

        self.orientation = orientation
        self.value = value
    }
} 

let x = Line(.Horizontal, 20.0)

// if you want that syntax 'Line.Horizontal(0.0)' you could fake it like this

struct Line {

    let orientation : Orientation
    let value : CGFloat

    private init(_ orientation: Orientation, _ value: CGFloat) {

        self.orientation = orientation
        self.value = value
    }

    static func Horizontal(value: CGFloat) -> Line { return Line(.Horizontal, value) }
    static func Vertical(value: CGFloat) -> Line { return Line(.Vertical, value) }
}

let y = Line.Horizontal(20.0)
Run Code Online (Sandbox Code Playgroud)