how to define an array of a particular enum case in swift - swift

I want to define an enum case which is recursively defined by a particular instance of the same enum
enum Menu {
case item(String)
case submenu([.item]) // i want a submenu to be defined by an array of items
}
the submenu case isn't correct:
case submenu([.item])
how can I confine it?

All cases of an enum are of the same enum type, so you cannot declare an Array that can only hold a specific case of an enum.
However, you can achieve your goals by creating 2 enums instead of one and making the Menu.submenu enum case take the other enum as its associated value.
enum Menu {
case item(MenuItem)
case submenu([MenuItem])
}
enum MenuItem {
case item(String)
}
Then you can use it like
let menu = Menu.item(.item("main"))
let submenu = Menu.submenu([.item("a"), .item("b")])

Related

Swift - Nested enums - how to perform same action on all nested enums with associated values?

I want to print the raw value of nested enums. For example, if I have a top level Food enum with multiple cases (for simplicity let's just say two: fruit, veggie), each of which are string enums (Fruit: String, Vegetable: String, etc), is there a way to print the inner associated values without doing a switch statement one the top level enum?
My current code is below. As you can see, the more cases I add to Food, the more redundant code will end up in var description. I'd like to write one action for all cases that prints the rawValue of the inner enums.
Is that possible without the switch?
enum Foods {
case fruit(Fruit)
case veggie(Vegetable)
var description: String { // this is what I'd like to replace
switch self {
case .fruit(let type):
return type.rawValue // since every case will look like this
case .veggie(let type):
return type.rawValue
}
}
}
enum Fruit: String {
case apple = "Apple"
case banana = "Banana"
}
enum Vegetable: String {
case carrot = "Carrot"
case spinach = "Spinach"
}
Is that possible without the switch?
No, this is not currently possible.
Workaround: I've noticed a pattern with your enum case names. The raw values of each are all capitalized versions of the case name i.e. case apple = "Apple". If this pattern always holds, you can use the following code:
var description: String { ("\(self)".split(separator: ".").last?.dropLast().capitalized)! }
Which will produce:
print(Foods.fruit(.apple).description) // Apple

How to get enum case name in Swift from within CustomStringConvertible implementation?

I have an enum that looks like this:
enum IntteruptCause: UInt8 {
case userDisplayDisengage = 0
case userSteeringWheelDisengage = 1
case positionDropout = 2
}
Currently the output from print() will give me the case name.
I would like to implment CustomStringConvertible and have it produce both the case name and the rawValue, e.g. the string User_Steering_Wheel_Disengage (1).
When I implement var description: String I have easy access to rawValue but I cannot seem to find out how to get the enum case name. Normally I would do String(describing: value) but that would create an infinite recursion if used in description implementation.
Is it possible to get the enum case name from within the description implementation?

swift - how to define an indirect enum case of a specific type

I want to define an enum representing a simplified version of a markdown document
I want something like the following but don't understand the syntax for defining the indirect enumerations
enum Markdown {
case text(String)
case sourceCode(code: String, language: Language)
indirect case tableCell(either "text" or "sourceCode")
indirect case tableRow(only table cells allowed)
indirect case table(only tableRow allowed)
}
Due to the documentation indirect enums can only refer to itself. A finer granularity is not possible. Your declaration should loo like
enum Markdown {
case text(String)
case sourceCode(code: String, language: String)
indirect case tableCell(Markdown)
indirect case tableRow([Markdown])
indirect case table([Markdown])
}
let t = Markdown.text("Hello")
let c = Markdown.tableCell(t)
You may also put the indirect keyword in front of the enum declaration to avoid its repetition:
indirect enum Markdown {
case text(String)
case sourceCode(code: String, language: String)
case tableCell(Markdown)
case tableRow([Markdown])
case table([Markdown])
}
You may define more type-safe enums:
indirect enum Content {
case text(String)
case bold(Content)
case italic(Content)
case span([Content])
}
indirect enum TableRow {
case tableCells([Content])
}
etc.
But I think that this leads very fast to other problems and you should rather work with structs or classes.

Is there an Object class in Swift?

I am very new to Swift. Is there a generic all-encompassing Object class in Swift like there is in Java/C#?
Can I declare an array that can hold anything (Int/String/Character...etc)?
As explained in "Why is there no universal base class in Swift?", no, but there is a common protocol that every type implicitly conforms to: Any.
// A statically typed `Any` constant, that points to a value which
// has a runtime type of `Int`
let something: Any = 5
// An array of `Any` things
let things: [Any] = [1, "string", false]
for thing in things {
switch thing {
case let i as Int: consumeInt(i)
case let s as String: consumeString(s)
case let b as Bool: consumeBool(b)
// Because `Any` really does mean ANY type, the compiler can't prove
// that this switch is exhaustive, unless we have a `default`
default: fatalError("Got an unexpected type!")
}
}
However, using Any is ill-advised most of the time. For most purposes, discriminated unions are a better choice, which Swift has in the form of enums. These ensure that all possible types are considered:
// Using an enum with associated values creates a discriminated union
// containing the exact set of type that we wish to support, rather than `Any`
enum SomeValue { // Note: this is a bad name, but just as an example!
case int(Int)
case string(String)
case bool(Bool)
}
let someValues: [SomeValue] = [.int(1), .string("string"), .bool(false)]
for value in someValues {
switch value {
case .int(let i): consumeInt(i)
case .string(let s): consumeString(s)
case .bool(let b): consumeBool(b)
// Enums have finitely many cases, all of which we exhausted here
// No `default` case required!
}
}
There are Anyand AnyObject types that are seem to what you search for. You can't extend them but you can up cast any object to AnyObject type and insert into [AnyObject] array. Any is more wide, and includes Int, String, Bool, etc.
No, Swift does not have a generic Object Class.

Can create enumeration as part of another enumeration?

I tried to create enum, which elements will be copied of another enum, like this:
enum Modes {
case mode1
case mode2
case additionalMode1
case additionalMode2
}
enum GeneralModes {
case mode1
case mode2
}
I have no idea how to do this. Need some backup.
Thanks for all answers and ideas.
You can't make an enum inherit from another enum and there is no built-in way to make your enum implement all cases that another enum implemented.
One possible workaround would be to give Modes a case with an associated value, which will be of type GeneralModes.
enum Modes {
case general(GeneralModes)
case additionalMode1
case additionalMode2
}
enum GeneralModes {
case mode1
case mode2
}
Then you can create a variable of type Modes with a value of mode1 like
let mode1 = Modes.general(.mode1)