Your two vehicle
s are being declared within the switch’s { }
, so they only exist in that block (that is their “scope”). They don’t exist outside it, so you can’t refer to them there, hence the error.
The default solution to this (that other answers are giving) is to declare the vehicle
as a var
outside the switch, but here’s an alternative: wrap the switch in a closure expression and return a value from it. Why do this? Because then you can use let
and not var
to declare vehicle
:
let vehicle: Vehicle = { // start of a closure expression that returns a Vehicle
switch classSetter {
case 1:
println("Initializing Car")
return Car()
case 2:
println("Initialized Bike")
return Bike()
default:
println("just defaulted")
return Vehicle()
}
}() // note the trailing () because you need to _call_ the expression
println("Name property from initialization is \(vehicle.name)")
It would be nice if if
and switch
were expressions (i.e. evaluated to a result) so you didn’t need this closure, but for now it’s a reasonable workaround.
Note, several of the answers here that use the var
approach suggest making vehicle
an Optional value (i.e. Vehicle?
). This is not necessary – so long as the code is guaranteed to assign vehicle
a value before it is used (and the compiler will check this for you), it doesn’t have to be optional. But I still think the closure expression version is a better way.
By the way, you might want to consider using a protocol for Vehicle
instead of a base class, since that way you don’t have to give Vehicle
a default but invalid implementation for name
:
protocol Vehicle {
var name: String { get }
}
// one of the benefits of this is you could
// make Car and Bike structs if desired
struct Car: Vehicle {
var name: String {return "Car"}
}
struct Bike: Vehicle {
var name: String {return "Bike"}
}
Though this would mean you couldn’t have a default return from the switch statement of a Vehicle()
. But chances are that would be bad anyway – an optional Vehicle?
with nil
representing failure might be a better option:
let vehicle: Vehicle? = {
switch classSetter {
case 1:
println("Initializing Car")
return Car()
case 2:
println("Initialized Bike")
return Bike()
default:
println("no valid value")
return nil
}
}()
// btw since vehicle is a Vehicle? you need to unwrap the optional somehow,
// one way is with optional chaining (will print (nil) here)
println("Name property from initialization is \(vehicle?.name)")
If you didn’t want this to be a possibility at all, you could consider making the indicator for different kinds of vehicles an enum so it could only be one of a valid set of vehicles:
enum VehicleKind {
case Bike, Car
}
let classSetter: VehicleKind = .Car
let vehicle: Vehicle = {
switch classSetter {
case .Car:
println("Initializing Car")
return Car()
case .Bike:
println("Initialized Bike")
return Bike()
// no need for a default clause now, since
// those are the only two possibilities
}
}()