Swift:如何添加可选整数

8

我声明以下内容:

var x:Int?
var y:Int?

我希望有一个第三个变量z,它包含xy的和。由于xy都是可选项,所以z也必须是可选项:

var z:Int? = x + y

但这会导致编译器错误 "可选类型'Int?'的值未解包; 你是否想使用'!'或'?' "

如果我解包xy

var z:Int? = x! + y!

我遇到了一个运行时错误,因为xy都是nil,所以无法解包。

我可以通过以下方法实现期望的结果:

var z:Int?

if let x1 = x {
    if let y1 = y {
       z = x1+y1
    }
}

但对于两个整数相加来说,这似乎有些冗长!有更好的方法实现吗?


2
你想忽略y或x中的任何一个为空吗?那么请使用 ?? 运算符。let z = (y ?? 0) + (x ?? 0) - Peheje
7个回答

4

我认为更简洁的写法如下:

let none:Int? = nil
let some:Int? = 2

func + (left: Int?, right:Int?) -> Int? {
    return left != nil ? right != nil ? left! + right! : left : right
}

println(none + none)
println(none + some)
println(some + none)
println(some + some)
println(2 + 2)

展示结果如下:

nil
Optional(2)
Optional(2)
Optional(4)
4

3

我认为最好的解决方案是:

z = x.map { x in y.map { $0 + x } }

你知道在 Optional<T> 上的 map 操作符吗?它非常好用。

文档说:

如果self为nil,则返回nil。否则,返回f(self!)。


1
不错,或者是flatMap - Au Ris
@AuRis 是的,你可以这样做,但是在这种情况下,flatMap 返回一个不需要的 Optional<T>,因为当有实际值返回时,我们肯定会返回某些内容。 - Fab1n
1
这是正确的思考问题的方式,做得好。 - Ray Toal

2

具体取决于您想要实现什么,但是您可以使用可选元组来完成:

var xy: (Int, Int)?
var z: Int

if let (x1, y1) = xy {
    z = x1 + y1 // Not executed
}
xy = (3, 4)
if let (x1, y1) = xy {
    z = x1 + y1 // 7
}
更新 正如@Jack Wu所指出的,这会改变语义。如果您愿意再详细一些,您可以按照以下方式进行操作:
func optIntAdd(x: Int?, y: Int?) -> Int? {
    if let x1 = x {
        if let y1 = y {
            return x1 + y1
        }
    }
    return nil
}

operator infix +! { }
@infix func +! (x: Int?, y: Int?) -> Int?{
    return optIntAdd(x, y)
}

var x: Int?
var y: Int?
var z: Int?

z =  x +! y // nil
x = 1
z =  x +! y // nil
y = 2
z =  x +! y // 3

我不确定“+!”是运算符名称的有用选择,但它不允许我选择“+?”。


这会改变事物的语义... xy 不能是 (3, nil) - Jack
1
正确。我看不出除了编写一个带有可选参数并返回可选项的函数之外,还有其他方法可以做到这一点,这似乎有点复杂 - 正如我在答案中所说,“这取决于您要实现什么。” - Grimxn
嗯...运算符重载和一个用于添加两个整数的函数...这不是Swift最好的时刻。 - Ashley Mills
2
啊...但它们不是整数 - 它们是可选的整数! :) - Grimxn

2
我能想到的最好的方案是:
if x && y {
    z = x! + y!;
}

由于它们都是可选的 (Optional)... 实际上无法避免:

  1. 检查它们不为 nil
  2. 在添加它们之前对其进行解包。

“为什么我想要可选整数?”:没有理由 - 这纯粹是理论上的。 - Ashley Mills
@AshleyMills 这种方法可以工作,但由于Swift语言应该更清晰明了,所以在维护期间理解这个例子会很困难。让你的代码简单易懂! - Maxim Shoustin
似乎“可选链”是一个不错的解决方案,但它只适用于对象方法、属性等。 - Ashley Mills
问题是关于Swift的 - 你的代码就是不起作用。 - Gargo

0

总有一天,我们会拥有可变泛型。但在那之前,您需要为所有元数准备一对重载。

var z = Optional(x, y).map(+)

public extension Optional {
  /// Exchange two optionals for a single optional tuple.
  /// - Returns: `nil` if either tuple element is `nil`.
  init<Wrapped0, Wrapped1>(_ optional0: Wrapped0?, _ optional1: Wrapped1?)
  where Wrapped == (Wrapped0, Wrapped1) {
    self = .init((optional0, optional1))
  }

  /// Exchange two optionals for a single optional tuple.
  /// - Returns: `nil` if either tuple element is `nil`.
  init<Wrapped0, Wrapped1>(_ optionals: (Wrapped0?, Wrapped1?))
  where Wrapped == (Wrapped0, Wrapped1) {
    switch optionals {
    case let (wrapped0?, wrapped1?):
      self = (wrapped0, wrapped1)
    default:
      self = nil
    }
  }
}

-1

Swift 5.5 对任何可选值求和

infix operator +?: AdditionPrecedence

public func +? <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T {
    if let lhs = lhs, let rhs = rhs {
        return lhs + rhs
    } else if let lhs = lhs {
        return lhs
    } else if let rhs = rhs {
        return rhs
    } else {
        return .zero
    }
}

-2

z = (x ?? 0) + (y ?? 0)

* 在 Xcode 9 上工作过 *


感谢确认。 - J. Murray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接