我来自C ++背景,但我正在为MetalKit学习Swift 4。由于我只习惯使用C ++,因此全部关注"选项"对我来说有点陌生。在阅读Apple发布的Swift 4书的同时,我遇到了以下问题:
说我有两个"字符串" s a和b:
let a = "12"
let b = "24"
我想将这两者加在一起。编写
是不好的做法和非法行为let c = Int(a) + Int(b)
因为a和b都是字符串,所以它们在Int中的类型转换是可选的:转换可能失败了。解决方案似乎是
if let c = Int(a), let d = Int(b)
{
let e = c + d
}
但这有点麻烦:我复制的方式比在C程序中更多,我可以简单地添加a和b,然后测试结果是否有值。是否有更有效,更好的方法来执行此添加?
答案 0 :(得分:1)
正如@rmaddy在评论中所说,这是选择的全部意义。它应该让你工作,从而产生更安全的代码。
如果您愿意进行一些前期工作,可以创建一个自定义运算符,如果结果转换为Int
nil
,则会抛出错误:
enum Err: Error {
case nilValue
}
func +(lhs: String, rhs: String)throws -> Int {
guard let c = Int(lhs), let d = Int(rhs) else {
throw Err.nilValue
}
return c + d
}
(您可能需要在此代码段中添加infix operator +
。)
然后您可以像这样使用它:
do {
let i: Int = try a + b
print(i)
} catch {
// Catch error here
}
或使用try?
。如果抛出错误,这将返回nil
:
let i: Int? = try? a + b
如果您不想使用类型注释,您可以给操作员一个不同的名称,即:
infix operator +?: AdditionPrecedence
func +?(lhs: String, rhs: String)throws -> Int
答案 1 :(得分:1)
如果您正在寻找一种方法来写一行,您可以利用map
和flatMap
变体来获得选项:
let a = "12"
let b = "24"
let c = Int(a).flatMap { aʹ in Int(b).map { bʹ in aʹ + bʹ }}
c
的类型为Optional<Int>
,nil
或Int(a)
失败时为Int(b)
。外部地图操作必须是flatMap
才能获得正确的结果类型。如果您将flatMap
替换为map
,则c
的类型将为Optional<Optional<Int>>
或Int??
。
您是否认为这种可读性至少部分是因为熟悉映射选项的概念。根据我的经验,大多数Swift开发人员更喜欢使用if let
进行展开,即使这会产生多行。
另一种选择:包装这种展开两个选项的模式,并将函数应用于泛型函数中的展开值:
func unwrapAndApply<A, B, Result>(_ a: A?, _ b: B?, _ f: (A, B) -> Result) -> Result? {
guard let a = a, let b = b else { return nil }
return f(a, b)
}
此函数适用于所有输入,无论基础类型如何。现在你可以写这个来执行添加:
let d = unwrapAndApply(Int(a), Int(b), +)
unwrapAndApply
函数仅适用于两个输入参数。如果您需要三个,四个,五个......输入的相同功能,则必须编写额外的unwrapAndApply
重载,这些重载将获取相应数量的参数。
答案 2 :(得分:0)
除了您展示的if let
方法之外,还有几种方法可以处理选项。
一种是在您使用选项的代码块的开头放置一个guard let
语句。这样可以避免大量嵌套if let
语句:
guard let c = Int(a), let d = Int(b) else { return }
// use `c` and `d` as you please
// ...
您还可以使用nil coalescing运算符来定义默认值(例如0):
let c = (Int(a) ?? 0) + (Int(b) ?? 0)
在这种情况下,如果Int(a)
或Int(b)
失败,它们将分别替换为0
。现在c
是Int
而不是Int?
,可以自由使用而无需解包。这可能适合也可能不适合,具体取决于使用默认值而非预期值时可能发生的情况。
进一步阅读:What is an optional value in Swift?
或者,您可以创建一个自定义运算符,以允许您以数字方式“添加”两个字符串:
infix operator +++: AdditionPrecedence
func +++(_ a: String, _ b: String) -> Int? {
if let intA = Int(a), let intB = Int(b) {
return intA + intB
} else {
return nil
}
}
// use it like so:
let c = "12" +++ "24"
// now c is Int? and you can check if the result is optional
if let d = c {
}
有关Swift文档中自定义运算符的更多信息:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html
答案 3 :(得分:0)
您可以通过多种方式执行此操作。如果你经常这样做,我会告诉你一个是合适的:
extension Int {
static func addStrings(_ firstString: String, _ secondString: String) -> Int? {
guard let firstNumber = Int(firstString) else { return nil }
guard let secondNumber = Int(secondString) else { return nil }
return firstNumber + secondNumber
}
}
你应该像这样使用它:
let number = Int.addStrings("1", "2")
我正在使用Swift的一个很棒的功能 - 扩展。使用它们,您可以将方法和计算变量添加到您想要的每个类。在Swift开发方面,可选项和扩展是非常重要的事情。您应该仔细阅读Apple文档。
答案 4 :(得分:0)
您可以定义自己的运算符以将两个选项组合在一起:
let a = "12"
let b = "24"
infix operator ?+: AdditionPrecedence
func ?+ (left: Int?, right: Int?) -> Int? {
guard let left = left,
let right = right else {
return nil
}
return left + right
}
let c = Int(a) ?+ Int(b)
结果是可选的。如果您不希望结果是可选的,则需要提供合适的默认值。例如,如果你认为0是合适的:
infix operator ?+: AdditionPrecedence
func ?+ (left: Int?, right: Int?) -> Int {
guard let left = left,
let right = right else {
return 0
}
return left + right
}