“ + +”和“——”运算符已经不推荐使用 Xcode 7.3

我在查看 Xcode 7.3注释时注意到了这个问题。

已不推荐使用 + + 和——运算符

有人能解释一下为什么它被弃用吗?我说的对吗,在 Xcode 的新版本中,你们将使用这个 abc1代替 ++;

例如:

for var index = 0; index < 3; index += 1 {
print("index is \(index)")
}

Screenshot for warning

72847 次浏览

来自 医生:

Swift 中的递增/递减运算符在 斯威夫特的发展,作为从 C。这些被增加 没有太多的考虑,从那以后也没有想过太多 然后。这个文件提供了一个全新的视角,并最终 建议我们只是完全删除他们,因为他们是混淆和 没有承受他们的重量。

斯威夫特的创造者克里斯 · 拉特纳(Chris Lattner)的 详细解释。我将总结一下要点:

  1. 这是另一个功能,你必须学习,而学习斯威夫特
  2. x += 1短不了多少
  3. Swift 不是 C 语言,不应该为了取悦 C 语言程序员而把它们带过来
  4. 它的主要用途是 C 风格的 for loop: for i = 0; i < n; i++ { ... },Swift 有更好的选择,比如 for i in 0..<n { ... }(C 风格的 for loop 是 也出去了)
  5. 阅读和维护可能很棘手,例如,x - ++xfoo(++x, x++)的值是多少?
  6. Chris Lattner 不喜欢这样。

对于那些感兴趣的人(以及为了避免链接腐败) ,拉特纳用自己的话说,他的理由是:

  1. 这些操作符增加了学习 Swift 作为第一种编程语言的负担——或者在其他情况下,您不知道这些操作符来自不同的语言。

  2. 它们的表达优势是极小的-x + + 不比 x + = 1短多少。

  3. Swift 已经偏离了 C,因为 = 、 + = 和其他类似赋值的操作返回 Void (原因有很多)。这些运算符与该模型不一致。

  4. Swift 具有强大的特性,可以消除在其他语言的 C 风格 for 循环中使用 + + i 的许多常见原因,因此在编写良好的 Swift 代码中相对较少使用这些特性。这些特性包括 for-in 循环、范围、枚举、映射等。

  5. 实际使用这些运算符的结果值的代码对于代码的读取者/维护者来说常常是令人困惑和难以捉摸的。他们鼓励“过于棘手”的代码,这可能是可爱的,但难以理解。

  6. 虽然 Swift 有定义良好的求值顺序,但任何依赖于它的代码(如 foo (+ + a,a + +))即使定义良好也是不受欢迎的。

  7. 这些运算符适用于相对较少的类型: 整数和浮点标量,以及类似迭代器的概念。它们不适用于复数、矩阵等。

最后,这些都不符合“如果我们还没有这些,我们会把它们添加到 Swift 3中吗?”

克里斯 · 拉特纳参加了反对 + + 和——的战争。他写道,“实际上使用这些操作符的结果值的代码对于代码的读者/维护者来说常常是令人困惑和难以捉摸的。他们鼓励“过于棘手”的代码,这些代码可能很可爱,但是难以理解... ... 虽然 Swift 有定义良好的评估顺序,但是任何依赖它的代码(如 foo (+ + a,a + +))即使定义良好也是不受欢迎的... ... 这些都不符合“如果我们没有这些,我们会把它们添加到 Swift 3中吗?”

苹果公司希望保持“迅捷”这种简洁、清晰、不混淆、直截了当的语言,因此他们反对使用 + + 和——关键字。

var value : Int = 1


func theOldElegantWay() -> Int{
return value++
}


func theNewFashionWay() -> Int{
let temp = value
value += 1
return temp
}

这绝对是个缺点,对吧?

苹果移除了 ++,并用另一种传统的方式使其更加简单。

您需要编写 +=,而不是 ++

例如:

var x = 1


//Increment
x += 1 //Means x = x + 1

类似地,对于递减运算符 --,您需要编写 -=

例如:

var x = 1


//Decrement
x -= 1 //Means x = x - 1

对于 for循环:

递增例子:

而不是

for var index = 0; index < 3; index ++ {
print("index is \(index)")
}

你可以写:

//Example 1
for index in 0..<3 {
print("index is \(index)")
}


//Example 2
for index in 0..<someArray.count {
print("index is \(index)")
}


//Example 3
for index in 0...(someArray.count - 1) {
print("index is \(index)")
}

减价例子:

for var index = 3; index >= 0; --index {
print(index)
}

你可以写:

for index in 3.stride(to: 1, by: -1) {
print(index)
}
//prints 3, 2


for index in 3.stride(through: 1, by: -1) {
print(index)
}
//prints 3, 2, 1


for index in (0 ..< 3).reverse() {
print(index)
}


for index in (0 ... 3).reverse() {
print(index)
}

希望这个能帮上忙!

我意识到这个评论并没有回答这个问题,然而,可能有人在寻找一个解决方案,如何保持这些操作员的工作,这样的解决方案可以在底部找到。

我个人更喜欢 ++--操作员。我不同意他们很狡猾或者难以管理的观点。一旦开发人员理解了这些操作符的作用(我们讨论的是非常简单的东西) ,代码就应该非常清楚了。

在解释为什么不推荐使用运算符时提到,它们的主要用途是使用 C 风格的 for 循环。我不知道其他人,但我个人根本不使用 C 风格的循环,当 ++--操作符有用时,还有许多其他地方或情况。

我还想提到的是,varName++返回一个值,因此它可以在 return中使用,而 varName += 1不能。

对于任何想让这些操作员继续在这里工作的人来说,解决方案是:

prefix operator ++ {}
postfix operator ++ {}


prefix operator -- {}
postfix operator -- {}




// Increment
prefix func ++(inout x: Int) -> Int {
x += 1
return x
}


postfix func ++(inout x: Int) -> Int {
x += 1
return (x - 1)
}


prefix func ++(inout x: UInt) -> UInt {
x += 1
return x
}


postfix func ++(inout x: UInt) -> UInt {
x += 1
return (x - 1)
}


prefix func ++(inout x: Int8) -> Int8 {
x += 1
return x
}


postfix func ++(inout x: Int8) -> Int8 {
x += 1
return (x - 1)
}


prefix func ++(inout x: UInt8) -> UInt8 {
x += 1
return x
}


postfix func ++(inout x: UInt8) -> UInt8 {
x += 1
return (x - 1)
}
prefix func ++(inout x: Int16) -> Int16 {
x += 1
return x
}


postfix func ++(inout x: Int16) -> Int16 {
x += 1
return (x - 1)
}


prefix func ++(inout x: UInt16) -> UInt16 {
x += 1
return x
}


postfix func ++(inout x: UInt16) -> UInt16 {
x += 1
return (x - 1)
}


prefix func ++(inout x: Int32) -> Int32 {
x += 1
return x
}


postfix func ++(inout x: Int32) -> Int32 {
x += 1
return (x - 1)
}


prefix func ++(inout x: UInt32) -> UInt32 {
x += 1
return x
}


postfix func ++(inout x: UInt32) -> UInt32 {
x += 1
return (x - 1)
}


prefix func ++(inout x: Int64) -> Int64 {
x += 1
return x
}


postfix func ++(inout x: Int64) -> Int64 {
x += 1
return (x - 1)
}


prefix func ++(inout x: UInt64) -> UInt64 {
x += 1
return x
}


postfix func ++(inout x: UInt64) -> UInt64 {
x += 1
return (x - 1)
}


prefix func ++(inout x: Double) -> Double {
x += 1
return x
}


postfix func ++(inout x: Double) -> Double {
x += 1
return (x - 1)
}


prefix func ++(inout x: Float) -> Float {
x += 1
return x
}


postfix func ++(inout x: Float) -> Float {
x += 1
return (x - 1)
}


prefix func ++(inout x: Float80) -> Float80 {
x += 1
return x
}


postfix func ++(inout x: Float80) -> Float80 {
x += 1
return (x - 1)
}


prefix func ++<T : _Incrementable>(inout i: T) -> T {
i = i.successor()
return i
}


postfix func ++<T : _Incrementable>(inout i: T) -> T {
let y = i
i = i.successor()
return y
}


// Decrement
prefix func --(inout x: Int) -> Int {
x -= 1
return x
}


postfix func --(inout x: Int) -> Int {
x -= 1
return (x + 1)
}


prefix func --(inout x: UInt) -> UInt {
x -= 1
return x
}


postfix func --(inout x: UInt) -> UInt {
x -= 1
return (x + 1)
}


prefix func --(inout x: Int8) -> Int8 {
x -= 1
return x
}


postfix func --(inout x: Int8) -> Int8 {
x -= 1
return (x + 1)
}


prefix func --(inout x: UInt8) -> UInt8 {
x -= 1
return x
}


postfix func --(inout x: UInt8) -> UInt8 {
x -= 1
return (x + 1)
}
prefix func --(inout x: Int16) -> Int16 {
x -= 1
return x
}


postfix func --(inout x: Int16) -> Int16 {
x -= 1
return (x + 1)
}


prefix func --(inout x: UInt16) -> UInt16 {
x -= 1
return x
}


postfix func --(inout x: UInt16) -> UInt16 {
x -= 1
return (x + 1)
}


prefix func --(inout x: Int32) -> Int32 {
x -= 1
return x
}


postfix func --(inout x: Int32) -> Int32 {
x -= 1
return (x + 1)
}


prefix func --(inout x: UInt32) -> UInt32 {
x -= 1
return x
}


postfix func --(inout x: UInt32) -> UInt32 {
x -= 1
return (x + 1)
}


prefix func --(inout x: Int64) -> Int64 {
x -= 1
return x
}


postfix func --(inout x: Int64) -> Int64 {
x -= 1
return (x + 1)
}


prefix func --(inout x: UInt64) -> UInt64 {
x -= 1
return x
}


postfix func --(inout x: UInt64) -> UInt64 {
x -= 1
return (x + 1)
}


prefix func --(inout x: Double) -> Double {
x -= 1
return x
}


postfix func --(inout x: Double) -> Double {
x -= 1
return (x + 1)
}


prefix func --(inout x: Float) -> Float {
x -= 1
return x
}


postfix func --(inout x: Float) -> Float {
x -= 1
return (x + 1)
}


prefix func --(inout x: Float80) -> Float80 {
x -= 1
return x
}


postfix func --(inout x: Float80) -> Float80 {
x -= 1
return (x + 1)
}


prefix func --<T : BidirectionalIndexType>(inout i: T) -> T {
i = i.predecessor()
return i
}


postfix func --<T : BidirectionalIndexType>(inout i: T) -> T {
let y = i
i = i.predecessor()
return y
}

Screenshot for warning

对此,Xcode 资本商业银行(Fix-it feature)给出了明确的答案。

Solution to warning

用老式的 value += 1(简易操作员)代替 ++ increment operator,用 value -= 1代替 -- decrement operator

对于 Swift 4,可以将 ++--操作符还原为 Int和其他类型的扩展。这里有一个例子:

extension Int {
@discardableResult
static prefix func ++(x: inout Int) -> Int {
x += 1
return x
}


static postfix func ++(x: inout  Int) -> Int {
defer {x += 1}
return x
}


@discardableResult
static prefix func --(x: inout Int) -> Int {
x -= 1
return x
}


static postfix func --(x: inout Int) -> Int {
defer {x -= 1}
return x
}
}

对于其他类型,如 UIIntInt8FloatDouble等,它的工作方式是相同的。

您可以将这些扩展名粘贴到根目录中的单个文件中,这些扩展名可以在根目录中的所有其他文件中使用。如果你在操场上检查一下,就会发现它非常完美。

在 Swift 4.1中,可以这样实现:




prefix operator ++
postfix operator ++
extension Int{
static prefix func ++(x: inout Int)->Int{
x += 1
return x
}
static postfix func ++(x: inout Int)->Int{
x += 1
return x-1
}
}
//example:
var t = 5
var s = t++
print("\(t) \(s)")



请注意,尽管这个解决方案与本文之前的解决方案类似,但它们在 Swift 4.1中不再有效,而这个例子可以。 还要注意,无论上面谁提到 + = 是 + + 的替代品,只是没有完全理解操作符,因为 + + 与赋值相结合实际上是两个操作,因此是一个快捷方式。 在我的例子中: var s = t++做两件事: 将 t 的值赋给 s,然后递增 t。如果 + + 出现在前面,那么这两个操作将以相反的顺序执行。 在我看来,苹果公司关于为什么删除这个操作符的推理(在前面的答案中提到)不仅是错误的推理,而且我认为这是一个谎言,真正的原因是他们不能让他们的编译器处理它。在以前的版本中,它给他们带来了麻烦,所以他们放弃了。 “太复杂以至于无法理解操作符,因此删除了”的逻辑显然是一个谎言,因为 Swift 包含的操作符要复杂得多,而且没有删除的操作符要少得多。而且,绝大多数编程语言都有这种特性。 JavaScript,C,C # ,Java,C + + 等等,程序员们很乐意使用它。 无论对于谁来说理解这个运算符太难,他们都应该而且只有他们才应该使用 + = (或者如果 + = 也太复杂的话,也可以使用 s = s + 1)。

Swift 背后的策略很简单: 苹果认为程序员很笨,因此应该得到相应的对待。

事实上,2014年9月发布的 Swift 应该已经在别的地方了。其他语言发展得更快。

我可以列出该语言中的许多主要错误,从严重的错误: 比如通过值粘贴而不是通过引用粘贴的数组,到恼人的错误: 可变参数函数不能接受数组,而这正是数组背后的全部思想。 我不认为苹果的员工被允许查看其他语言,比如 Java,所以他们甚至不知道苹果落后了几光年。苹果本可以采用 Java 作为一种语言,但如今,挑战不再是技术,而是自我。 如果他们打开 IntelliJ 编写一些 Java,他们肯定会关闭他们的业务理解,在这一点上,他们不能,也不会赶上来。

下面是迄今为止发布的一些代码的通用版本。我想表达和其他人一样的担忧: 在 Swift 中使用 没有是一个最佳实践。我同意这可能会让那些将来阅读您的代码的人感到困惑。

prefix operator ++
prefix operator --
prefix func ++<T: Numeric> (_ val: inout T) -> T {
val += 1
return val
}


prefix func --<T: Numeric> (_ val: inout T) -> T {
val -= 1
return val
}


postfix operator ++
postfix operator --
postfix func ++<T: Numeric> (_ val: inout T) -> T {
defer { val += 1 }
return val
}


postfix func --<T: Numeric> (_ val: inout T) -> T {
defer { val -= 1 }
return val
}

这也可以写成 Numeric 类型的扩展。

由于您从来没有真正使用 Swift 中的指针,所以在我看来,删除 ++--操作符是有意义的。然而,如果你离不开它,你可以将这些 Swift 5 + 操作符声明添加到你的项目中:

@discardableResult
public prefix func ++<T: Numeric>(i: inout T) -> T {
i += 1
return i
}


@discardableResult
public postfix func ++<T: Numeric>(i: inout T) -> T {
defer { i += 1 }
return i
}


@discardableResult
public prefix func --<T: Numeric>(i: inout T) -> T {
i -= 1
return i
}


@discardableResult
public postfix func --<T: Numeric>(i: inout T) -> T {
defer { i -= 1 }
return i
}

在没有分号的语言中,它可能是模糊的。它是前缀还是后缀操作符?

考虑一下:

var x = y
++x

人工读取 ++x,但解析器可以将其读取为 y++