Aju Antony
Aju Antony

Reputation: 639

How to use nested constants in Swift

Using enums for constants seems to be a simple and elegant solution. Is there a way I can achieve a nested string output using enums?

For example, consider I have the following piece of code:

enum Const {
    enum Car {
        static let Door = "Door"
        static let Engine = "Engine"
    }
}

Is there anyway that I can get "Car| Door" as an output for Const.Car.Door? or "Car| Engine" as output for Const.Car.Engine? and "Car" as output for Const.Car?. I have some analytics constants defined in my current project similar to namespace pattern. It has a LOT of nested tracking events and would really help if I can achieve what I just described above.

What I require:

Const.Car should give the output "Car"

Const.Car.Door should give the output "Car| Door"

Const.Car.Engine should give the output "Car| Engine"

I have no idea on how to achieve that.

EDIT:

This should be also be extendable,

For example,

Const.Car.Door.Handle should give the output "Car| Door| Handle"

Const.Plane should give the output "Plane"

Const.Plane.Flaps should give the output "Plane| Flaps"

Upvotes: 2

Views: 801

Answers (4)

XmasRights
XmasRights

Reputation: 1509

Cleanest way I can think of is:

struct Const
{
    enum Car: String, CustomStringConvertible
    {
        case Door
        case Engine

        var description: String
        {
            return "Car\(self.rawValue)"
        }
    }
}

print("\(Const.Car.Door)")    // CarDoor
print("\(Const.Car.Engine)")  // CarEngine

Achieves what you need, makes it really easy to add new cases/parts without any boilerplate, and it would be simple to abstract away this functionality if you wish to support more vehicles.

Upvotes: 1

Alexander Tkachenko
Alexander Tkachenko

Reputation: 3281

Operator overloading may help you to achieve similar functionality. Please look at my solution, you can extend it a lot more

enum Vehicle: String {
    case car = "Car"
    case airplane = "Airplane"

    enum CarPart: String {
        case door = "Door"
        case window = "Window"
    }
}

func > (left: Vehicle, right: Vehicle.CarPart) -> String {
    return left.rawValue + right.rawValue
}


let string = .car > .window // "CarWindow"

Upvotes: 3

Hodson
Hodson

Reputation: 3556

This doesn't exactly fulfil your requirements as it doesn't print "Car" when calling Const.Car but it may be somewhere for you to start:

enum Const {
    enum Car {
        static let identifier = "Car"
        static let Door = "\(Car.identifier)Door"
        static let Engine = "\(Car.identifier)Engine"
    }
}

print(Const.Car.Door) //CarDoor
print(Const.Car.Engine) //CarEngine

You can print "Car" by calling Const.Car.identifier though.

Upvotes: 1

juliancadi
juliancadi

Reputation: 1024

I had a time ago a similar problem which I managed to solve using struct and enum. In your case it would look like this:

struct Const{
   enum Car: String {
      case Door = "CarDoor"
      case Engine = "CarEngine"
   }
}

print("\(Const.Car.Door)") //CarDoor
print("\(Const.Car.Engine)") //CarEngine

I hope it fits you well.

Upvotes: 1

Related Questions