【问题标题】:Understanding precedence group's assignment in Swift 3.1理解 Swift 3.1 中优先组的分配
【发布时间】:2017-12-21 09:58:57
【问题描述】:

Swift 允许定义我们自己的优先级组以用于我们的自定义运算符。我很难理解一件事,那就是布尔 assignment 属性。

来自Swift 编程语言(Swift 3.1)

优先级组的分配指定运算符在包含可选链接的操作中使用时的优先级。当设置为true 时,相应优先级组中的运算符在可选链接期间使用与标准库中的赋值运算符相同的分组规则。否则,当设置为 false 或省略时,优先组中的运算符遵循与不执行赋值的运算符相同的可选链接规则。

它并没有说明assignment 属性的确切行为。可选链中的赋值运算符和非赋值运算符有什么区别?

我定义了++=(行为类似于+=)和++(行为类似于+)运算符以及用于测试的AssignmentTesting结构。

precedencegroup AssignmentTrue {
    assignment: true
}

precedencegroup AssignmentFalse {
    assignment: false
}

infix operator ++=: AssignmentTrue
infix operator ++: AssignmentFalse

extension Int {
    static func ++= (left: inout Int, right: Int) {
        left += right
    }

    static func ++ (left: Int, right: Int) -> Int {
        return left + right
    }
}

struct AssignmentTesting { var number = 0 }

var assignmentTesting: AssignmentTesting? = AssignmentTesting()
assignmentTesting?.number ++= 3 // assigns 0 + 3 to assignmentTesting.number
assignmentTesting!.number ++ 5 // returns 3 + 5
assignmentTesting?.number // == 3

assignment: trueassignment: false 如何影响这些行为?非常欢迎任何解释。

【问题讨论】:

    标签: swift swift3 operators


    【解决方案1】:

    您的示例代码很好地描述了差异:

    // assigns (assignmentTesting!.number + 3) to assignmentTesting!.number when assignmentTesting != nil
    // Do nothing when assignmentTesting == nil
    assignmentTesting?.number ++= 3
    
    // assigns (assignmentTesting!.number + 3) to assignmentTesting!.number when assignmentTesting != nil
    // Crashing when assignmentTesting == nil
    assignmentTesting!.number ++= 3
    
    // Does not compile
    //assignmentTesting?.number ++ 5
    
    // returns (assignmentTesting!.number + 5) when assignmentTesting != nil
    // Crashing when assignmentTesting == nil
    assignmentTesting!.number ++ 5
    

    ++= 是赋值运算符时,像assignmentTesting?.number ++= 3 这样的可选链的工作方式非常类似于:

    (assignmentTesting != nil) ? (assignmentTesting!.number ++= 3) as Void?  : nil
    

    但是当++ 不是赋值运算符时,assignmentTesting?.number ++ 5 在 Swift 中不是一个有效的表达式并且不能作为:

    (assignmentTesting != nil) ? (assignmentTesting!.number ++ 5) as Int? : nil
    

    【讨论】:

    • 我还是不明白其中的区别。为什么不能只是 inout 参数的性质处理呢?我找到了关于 Swift 2.2 行为的很好的解释,我猜这和我猜的一样:"Swift 2.2 有赋值修饰符,其工作方式如下:一个操作符标记的赋值被折叠到一个可选链中,允许 foo?.bar += 2 像 @987654329 一样工作@ 而不是无法将类型检查为 (foo?.bar) += 2。此行为将传递给 assignment:在优先级组上为 true。”,但对我来说仍然很模糊。
    • 它描述了在 Swift 2 中声明赋值运算符的语法,语义或行为与 Swift 3 相同。您可能需要定义其他使用 inout 的运算符,但行为 不需要用于分配的可选链接
    • 你能详细解释一下赋值运算符和非赋值运算符之间的可选链接有什么区别吗?我很好奇为什么只需要另一个参数来处理可选链接中的赋值。在precedencegroup 中引入新语法必须足够重要。
    • @RoboRobok,已经包含在我的答案中。请仔细阅读。没有它,Swift 编译器如何解析a?.property <op> b?它应该会导致诊断错误可选值a?.property 未解包。你的意思是! 还是? 还是应该编译为 Optional 链接进行赋值?
    • 我仔细看了还是没看懂,抱歉。你能根据一些现有的运营商举个例子吗?
    【解决方案2】:

    对差异的简单解释是,如果您在可选链接期间使用不可分配的运算符,则无法编译代码。

    在您的示例中,您设置了assignmentTesting?.number ++= 3,其中++= 尝试与+= 表现相同。但是,正如assignment: false优先级组中的运算符遵循与不执行赋值的运算符相同的可选链接规则。没有执行赋值,所以编译器报错。

    因此,您需要在AssignmentPrecedence 中添加++= 以使其在可选链接期间可分配。

    infix operator ++=: AssignmentPrecedence
    

    precedencegroup AssignmentTrue {
        assignment: true
    }
    infix operator ++=: AssignmentTrue
    

    更新

    您的示例实际上是不言自明的,并且您还指出 一个运算符标记的赋值被折叠到一个可选链中,允许 foo?.bar += 2 作为 foo?(.bar += 2) 工作,而不是无法作为 @987654332 进行类型检查@。此行为将传递给 assignment: true on 来自SE-0077 的优先组

    • 如果将assignmentTesting 声明为可选,但不在AssignmentPrecedence 组中添加++=,编译器会将语句视为assignmentTesting?.number += 3。它不会知道(assignmentTesting?.number) 是否会返回nil。因此它将无法编译。

    • 1234563它在编译时经过类型检查并证明是正确的。该语句将通过,因为number += 3 将优先于可选链接。
    • 如果您强制解开 assignmentTesting,则语句将为 assignmentTesting!.number += 3。正如您确定assignmentTesting 不会是nil,编译器不会抱怨。但是,如果在运行时,assignmentTesting 解包失败,则会触发运行时错误。

    【讨论】:

    • 这一切我都知道。您的回答没有解释会发生什么。
    • 我在你的例子中玩了一段时间,并且在给出答案之前还通读了你和@OOPer 之间的对话,并认为提及它是多余的,但我还是更新了我的答案。不知道为什么它仍然困扰你很多,但如果你仍然是,对不起,我无能为力。其他人可能会给出更好的解释。
    【解决方案3】:

    二元运算符,即使是执行赋值的运算符,也可能包含在assignment: true 的优先级组中。在这种情况下,如果左操作数使用可选链(并且不会因为它是 nil 而失败),则运算符将作用于隐藏在可选链后面的值。返回的结果仍然是可选的。

    assignment: false 的情况下,操作员只会将操作数视为可选项,而不是所需的值类型,然后会出现错误。

    在您的代码中,替换以下行:

     assignmentTesting!.number ++ 5
    

    用线:

    assignmentTesting?.number ++ 5
    

    如果您将AssignmentFalse 设置为运算符++ 的优先组,则会出现错误。如果设置AssignmentTrue,它将起作用,将隐藏在Optional后面的值3加5,并返回Optional(8)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-21
      • 1970-01-01
      • 2021-07-23
      • 2017-07-01
      • 2015-05-13
      • 1970-01-01
      • 2015-03-09
      • 1970-01-01
      相关资源
      最近更新 更多