¿Proporciona un valor predeterminado para un Opcional en Swift?

141

El modismo para tratar con las opciones en Swift parece excesivamente detallado, si todo lo que desea hacer es proporcionar un valor predeterminado en el caso en que sea nulo:

if let value = optionalValue {
    // do something with 'value'
} else {
    // do the same thing with your default value
}

que implica duplicar código innecesariamente, o

var unwrappedValue
if let value = optionalValue {
    unwrappedValue = value
} else {
    unwrappedValue = defaultValue
}

lo cual requiere unwrappedValueno ser una constante.

La mónada Option de Scala (que es básicamente la misma idea que la Opcional de Swift) tiene el método getOrElsepara este propósito:

val myValue = optionalValue.getOrElse(defaultValue)

¿Me estoy perdiendo de algo? ¿Swift ya tiene una forma compacta de hacerlo? O, en su defecto, ¿es posible definir getOrElseen una extensión para Opcional?

Wes Campaigne
fuente

Respuestas:

289

Actualizar

Apple ahora ha agregado un operador de fusión:

var unwrappedValue = optionalValue ?? defaultValue

El operador ternario es tu amigo en este caso

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

También puede proporcionar su propia extensión para la enumeración opcional:

extension Optional {
    func or(defaultValue: T) -> T {
        switch(self) {
            case .None:
                return defaultValue
            case .Some(let value):
                return value
        }
    }
}

Entonces solo puedes hacer:

optionalValue.or(defaultValue)

Sin embargo, recomiendo apegarse al operador ternario ya que otros desarrolladores lo entenderán mucho más rápidamente sin tener que investigar el ormétodo.

Nota : Empecé un módulo de añadir ayudantes comunes como éste oren Optionalal veloz.

Drewag
fuente
mi compilador me muestra que el tipo de unwrappedValuesigue siendo el tipo opcional para este caso en Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). ¿Ha cambiado esto?
SimplGy
2
Estoy equivocado en mi versión. Estoy en 6.4. Tenga en cuenta: el ??comportamiento de inferencia de tipo predeterminado es que devuelve un opcional, que normalmente no es lo que desea. Puede declarar la variable como no opcional y esto funciona bien.
SimplGy
29

A partir de agosto de 2014, Swift tiene un operador coalescente (??) que lo permite. Por ejemplo, para un String myOptional opcional, podría escribir:

result = myOptional ?? "n/a"
MirekE
fuente
4

si escribiste:

let result = optionalValue ?? 50

y optionalValue != nilluego resultlo será optionaltambién y necesitarás desenvolverlo en el futuro

Pero puedes escribir operador

infix operator ??? { associativity left precedence 140 }

func ???<T>(optLeft:T?, right:T!) -> T!
{
    if let left = optLeft
    {
        return left
    }
    else { return right}
}

Ahora usted puede:

 let result = optionalValue ??? 50

Y cuando optionalValue != nilentonces resultseráunwraped

UnRewa
fuente
3

Lo siguiente parece funcionar

extension Optional {
    func getOrElse<T>(defaultValue: T) -> T {
        if let value = self? {
            return value as T
        } else {
            return defaultValue
        }
    }
}

Sin embargo, la necesidad de lanzar value as Tes un truco feo. Idealmente, debería haber una manera de afirmar que Tes el mismo que el tipo contenido en el Opcional. Tal como está, escriba conjuntos de inferencia Tbasados ​​en el parámetro dado a getOrElse, y luego falla en el tiempo de ejecución si esto no coincide con el Opcional y el Opcional no es nulo:

let x: Int?

let y = x.getOrElse(1.414) // y inferred as Double, assigned 1.414

let a: Int? = 5

let b: Double = a.getOrElse(3.14) // Runtime failure casting 5 to Double
Wes Campaigne
fuente
No necesita especificar Tel método. Eso realmente anula lo existente Tde Opcional. Usted sólo puede hacer: func getOrElse(defaultValue: T) -> Tentonces T se refiere al tipo de valor real de la opcional y usted no tiene que escribir comprobarlo
DREWAG
¡Gracias! Inferí exactamente eso de la segunda mitad de su respuesta. ¿Hay alguna forma de inspeccionar la definición de Opcional para saber que el tipo genérico se define así T? (más allá de simplemente asumir según la convención)
Wes Campaigne
Si hace clic en Comando Optionaldentro de Xcode, verá que se define comoenum Optional<T>
drewag
Oh excelente. Debí haberlo adivinado. Las definiciones allí serán útiles; Hay muchas cosas que todavía no están en la documentación. Gracias de nuevo.
Wes Campaigne