在Swift中为可选项提供默认值?

时间:2022-07-17 11:01:05

The idiom for dealing with optionals in Swift seems excessively verbose, if all you want to do is provide a default value in the case where it's nil:

在Swift中处理选项的习惯用法似乎过于冗长,如果您只想在为nil的情况下提供一个默认值:

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

which involves needlessly duplicating code, or

其中包括不必要的重复代码,还是

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

which requires unwrappedValue not be a constant.

它要求unwrappedValue不是常量。

Scala's Option monad (which is basically the same idea as Swift's Optional) has the method getOrElse for this purpose:

Scala的monad选项(与Swift的可选选项基本相同)具有用于此目的的getOrElse方法:

val myValue = optionalValue.getOrElse(defaultValue)

Am I missing something? Does Swift have a compact way of doing that already? Or, failing that, is it possible to define getOrElse in an extension for Optional?

我遗漏了什么东西?斯威夫特已经有了一种紧凑的方式了吗?或者,如果做不到这一点,是否可能在可选扩展中定义getOrElse ?

5 个解决方案

#1


212  

Update

更新

Apple has now added a coalescing operator:

苹果现在增加了一个合并运营商:

var unwrappedValue = optionalValue ?? defaultValue

The ternary operator is your friend in this case

在这种情况下,三元算符是你的朋友

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

You could also provide your own extension for the Optional enum:

您也可以为可选enum提供您自己的扩展:

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

Then you can just do:

然后你可以这样做:

optionalValue.or(defaultValue)

However, I recommend sticking to the ternary operator as other developers will understand that much more quickly without having to investigate the or method

但是,我建议坚持使用三元运算符,因为其他开发人员可以更快地理解这个操作,而不必研究or方法

Note: I started a module to add common helpers like this or on Optional to swift.

注意:我启动了一个模块来添加像这样的通用助手,或者在swift中可选的位置。

#2


23  

As of Aug 2014 Swift has coalescing operator (??) that allows that. For example, for an optional String myOptional you could write:

从2014年8月起,Swift就拥有了合并运营商(?? ?)例如,对于可选字符串myOptional,你可以写:

result = myOptional ?? "n/a"

#3


2  

if you wrote:

如果你写的:

let result = optionalValue ?? 50

and optionalValue != nil then result will be optional too and you will need unwrap it in future

还有optionalValue != nil结果也是可选的,以后你需要打开它

But you can write operator

但是你可以写算子

infix operator ??? { associativity left precedence 140 }

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

Now you can:

现在您可以:

 let result = optionalValue ??? 50

And when optionalValue != nil then result will be unwraped

当optionalValue != nil时,结果将被展开

#4


1  

The following seems to work

下面的内容似乎有用。

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

however the need to cast value as T is an ugly hack. Ideally, there should be a way to assert that T is the same as the type contained in the Optional. As it stands, type inferencing sets T based on the parameter given to getOrElse, and then fails at runtime if this does not match the Optional and the Optional is non-nil:

然而,将值转换为T是一种丑陋的做法。理想情况下,应该有一种方法来断言T与可选项中包含的类型相同。如前所述,类型推断根据给定的getOrElse参数设置T,如果不匹配可选和可选,则在运行时失败:

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

#5


1  

I've made an simple extension library and using it myself to reduce such a repetitive codes. It casts and returns optional primitive types into default value. You just cast it like below,

我做了一个简单的扩展库,自己使用它来减少重复的代码。它将可选的基本类型转换为默认值并返回。你只是把它像下面这样投射,

CGFloat(optionalValue)

or with certain default value,

或者有特定的默认值,

Int(optionalValue, defaultValue: 100)

You can look through this repository.

您可以查看这个存储库。

#1


212  

Update

更新

Apple has now added a coalescing operator:

苹果现在增加了一个合并运营商:

var unwrappedValue = optionalValue ?? defaultValue

The ternary operator is your friend in this case

在这种情况下,三元算符是你的朋友

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

You could also provide your own extension for the Optional enum:

您也可以为可选enum提供您自己的扩展:

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

Then you can just do:

然后你可以这样做:

optionalValue.or(defaultValue)

However, I recommend sticking to the ternary operator as other developers will understand that much more quickly without having to investigate the or method

但是,我建议坚持使用三元运算符,因为其他开发人员可以更快地理解这个操作,而不必研究or方法

Note: I started a module to add common helpers like this or on Optional to swift.

注意:我启动了一个模块来添加像这样的通用助手,或者在swift中可选的位置。

#2


23  

As of Aug 2014 Swift has coalescing operator (??) that allows that. For example, for an optional String myOptional you could write:

从2014年8月起,Swift就拥有了合并运营商(?? ?)例如,对于可选字符串myOptional,你可以写:

result = myOptional ?? "n/a"

#3


2  

if you wrote:

如果你写的:

let result = optionalValue ?? 50

and optionalValue != nil then result will be optional too and you will need unwrap it in future

还有optionalValue != nil结果也是可选的,以后你需要打开它

But you can write operator

但是你可以写算子

infix operator ??? { associativity left precedence 140 }

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

Now you can:

现在您可以:

 let result = optionalValue ??? 50

And when optionalValue != nil then result will be unwraped

当optionalValue != nil时,结果将被展开

#4


1  

The following seems to work

下面的内容似乎有用。

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

however the need to cast value as T is an ugly hack. Ideally, there should be a way to assert that T is the same as the type contained in the Optional. As it stands, type inferencing sets T based on the parameter given to getOrElse, and then fails at runtime if this does not match the Optional and the Optional is non-nil:

然而,将值转换为T是一种丑陋的做法。理想情况下,应该有一种方法来断言T与可选项中包含的类型相同。如前所述,类型推断根据给定的getOrElse参数设置T,如果不匹配可选和可选,则在运行时失败:

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

#5


1  

I've made an simple extension library and using it myself to reduce such a repetitive codes. It casts and returns optional primitive types into default value. You just cast it like below,

我做了一个简单的扩展库,自己使用它来减少重复的代码。它将可选的基本类型转换为默认值并返回。你只是把它像下面这样投射,

CGFloat(optionalValue)

or with certain default value,

或者有特定的默认值,

Int(optionalValue, defaultValue: 100)

You can look through this repository.

您可以查看这个存储库。