Fornecendo um valor padrão para um Opcional no Swift?

141

O idioma para lidar com opcionais no Swift parece excessivamente detalhado, se tudo o que você deseja fazer é fornecer um valor padrão no caso em que é nulo:

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

que envolve a duplicação desnecessária de código ou

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

o que unwrappedValuenão requer ser uma constante.

A mônada de Scala's Option (que é basicamente a mesma ideia que a Swift's Optional) possui o método getOrElsepara esse fim:

val myValue = optionalValue.getOrElse(defaultValue)

Estou esquecendo de algo? O Swift já tem uma maneira compacta de fazer isso? Ou, na sua falta, é possível definir getOrElseem uma extensão para Opcional?

Wes Campaigne
fonte

Respostas:

289

Atualizar

A Apple agora adicionou um operador coalescente:

var unwrappedValue = optionalValue ?? defaultValue

O operador ternário é seu amigo neste caso

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Você também pode fornecer sua própria extensão para a enumeração opcional:

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

Então você pode simplesmente fazer:

optionalValue.or(defaultValue)

No entanto, eu recomendo aderir ao operador ternário, pois outros desenvolvedores entenderão isso muito mais rapidamente sem precisar investigar o ormétodo

Nota : Eu comecei um módulo para adicionar auxiliares comuns como esta orem Optionalque rápida.

drewag
fonte
meu complier me mostra que o tipo de unwrappedValueainda é o tipo opcional para este caso no Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). Isso mudou?
SimplGy 14/08/2015
2
Estou errado na minha versão. Estou no 6.4. Esteja ciente: ??o comportamento de inferência de tipo padrão é que ele retorna um opcional, que não é o que você deseja normalmente. Você pode declarar a variável como não opcional e isso funciona bem.
SimplGy
29

Em agosto de 2014, a Swift tinha um operador coalescente (??) que permite isso. Por exemplo, para uma String opcional myOptional, você pode escrever:

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

se você escreveu:

let result = optionalValue ?? 50

e optionalValue != nilentão resultserá optionaltambém e você precisará desembrulhá-lo no futuro

Mas você pode escrever operador

infix operator ??? { associativity left precedence 140 }

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

Agora você pode:

 let result = optionalValue ??? 50

E quando optionalValue != nilentão resultseráunwraped

UnRewa
fonte
3

O seguinte parece funcionar

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

no entanto, a necessidade de lançar value as Té um truque feio. Idealmente, deve haver uma maneira de afirmar que Té igual ao tipo contido no Opcional. Como está, digite conjuntos de inferências com Tbase no parâmetro fornecido para getOrElse e falhe no tempo de execução se isso não corresponder ao Opcional e o Opcional for 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
fonte
Você não precisa especificar To método. Na verdade, isso substitui o existente Tdo Opcional. Você pode apenas fazer: func getOrElse(defaultValue: T) -> Tentão T refere-se ao tipo de valor real do opcional e você não tem que digitar verificá-lo
drewag
Obrigado! Eu deduzi exatamente isso a partir da segunda metade da sua resposta. Existe alguma maneira de inspecionar a definição de Opcional para saber que o tipo genérico é definido como Tnesse? (além de simplesmente assumir com base na convenção)
Wes Campaigne
Se você Command no Optionalinterior Xcode, você vai ver que ele é definido comoenum Optional<T>
drewag
Oh, excelente. Eu deveria ter adivinhado. As definições serão úteis; há muitas coisas que ainda não estão na documentação. Obrigado novamente.
9788 Wesleye