“++”和“--”运算符已被弃用 Xcode 7.3

The "++" and "--" operators have been deprecated Xcode 7.3

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

The ++ and -- operators have been deprecated

有人能解释一下为什么它被弃用了吗?我说得对吗,在 Xcode 的新版本中,现在您将使用 x += 1;

而不是 ++

示例:

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

来自docs

The increment/decrement operators in Swift were added very early in the development of Swift, as a carry-over from C. These were added without much consideration, and haven't been thought about much since then. This document provides a fresh look at them, and ultimately recommends we just remove them entirely, since they are confusing and not carrying their weight.

来自 Swift 的创建者 Chris Lattner 的 full explanation here。我总结一下要点:

  1. 又是一个边学边学的功能Swift
  2. 不比x += 1
  3. 短多少
  4. Swift 不是 C。不应该为了取悦 C 程序员而把它们带过来
  5. 它的主要用途是在 C 风格的 for 循环中:for i = 0; i < n; i++ { ... },Swift 有更好的选择,比如 for i in 0..<n { ... }(C 风格的 for 循环是 going out as well )
  6. 可能难以阅读和维护,例如,x - ++xfoo(++x, x++) 的值是多少?
  7. 克里斯拉特纳不喜欢它。

对于那些感兴趣的人(并避免 link 腐烂),Lattner 用他自己的话说是:

  1. These operators increase the burden to learn Swift as a first programming language - or any other case where you don't already know these operators from a different language.

  2. Their expressive advantage is minimal - x++ is not much shorter than x += 1.

  3. Swift already deviates from C in that the =, += and other assignment-like operations returns Void (for a number of reasons). These operators are inconsistent with that model.

  4. Swift has powerful features that eliminate many of the common reasons you'd use ++i in a C-style for loop in other languages, so these are relatively infrequently used in well-written Swift code. These features include the for-in loop, ranges, enumerate, map, etc.

  5. Code that actually uses the result value of these operators is often confusing and subtle to a reader/maintainer of code. They encourage "overly tricky" code which may be cute, but difficult to understand.

  6. While Swift has well defined order of evaluation, any code that depended on it (like foo(++a, a++)) would be undesirable even if it was well-defined.

  7. These operators are applicable to relatively few types: integer and floating point scalars, and iterator-like concepts. They do not apply to complex numbers, matrices, etc.

Finally, these fail the metric of "if we didn't already have these, would we add them to Swift 3?"

Chris Lattner war 反对 ++ 和 --。他写道,“实际使用这些运算符的结果值的代码通常会使 reader/maintainer 代码混乱和微妙。他们鼓励“过于棘手”的代码,这些代码可能很可爱,但难以理解……虽然 Swift 具有明确定义的评估顺序,但任何依赖于它的代码(如 foo(++a, a++))都将是即使定义明确也是不可取的……这些不符合“如果我们还没有这些,我们会把它们添加到 Swift 3 吗?”的指标?

Apple 希望保持 swift 一种干净、清晰、不混淆且直截了当的语言。因此他们弃用了 ++ 和 -- 关键字。

var value : Int = 1

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

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

这绝对是一个缺点,对吧?

Apple 删除了 ++ 并使用另一种古老的传统方式使其变得更加简单。

而不是++,你需要写+=

示例:

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++ returns 一个值,因此它可以在 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
}

Xcode的Fix-it feature对此给出了明确的回答。

++ increment operator替换为老式的value += 1(速记运算符),将-- decrement operator替换为value -= 1

对于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)")


请注意,尽管此解决方案与此 post 中的先前解决方案类似,但它们在 Swift 4.1 中不再有效,而本示例中可以。 另请注意,上面提到 += 是 ++ 的替代品的人只是不完全理解运算符,因为 ++ 结合赋值实际上是两个操作,因此是一个快捷方式。 在我的示例中:var s = t++ 做了两件事:将 t 的值赋给 s,然后递增 t。如果 ++ 出现在前面,则相同的两个操作以相反的顺序完成。 在我看来,Apple 关于为什么要删除此运算符的推理(在之前的答案中提到)不仅是错误的推理,而且我认为这是一个谎言,真正的原因是他们无法让编译器处理它。它在以前的版本中给他们带来了麻烦,所以他们放弃了。 "too complicated to understand operator, hence removed" 的逻辑显然是个谎言,因为 Swift 包含的运算符要复杂得多,用处也小得多,因此没有被删除。此外,绝大多数编程语言都有它。 JavaScript、C、C#、Java、C++ 等等。程序员愉快地使用它。 无论谁太难理解这个运算符,他们并且只有他们应该做 += (或者如果 += 也太复杂的话,也许 s = s + 1)。

Swift背后的策略很简单:Apple 认为程序员是愚蠢的,因此应该受到相应的对待。

事实是 Swift,于 2014 年 9 月推出,现在应该在其他地方了。其他语言发展得更快。

我可以列出语言中的许多主要错误,从严重的错误:例如按值而不是按引用粘贴的数组,到烦人的错误:可变参数函数不能接受数组,这是它背后的全部思想. 我不认为 Apple 的员工甚至被允许查看 Java 等其他语言,所以他们甚至不知道 Apple 落后了光年。苹果本可以采用 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
}

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

由于您从未真正使用过 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++