【问题标题】:Swift 3 Ranges: Best PracticesSwift 3 Ranges:最佳实践
【发布时间】:2016-07-03 15:31:48
【问题描述】:

我昨天下载了 Xcode 8.0 测试版,然后下载了 Swift 3。我做的第一件事是尝试为 Swift 3 更新我的项目,我差点哭了。最严重的变化之一是(在我看来)Swifts Range 结构的新管理,特别是因为自动转换为当前的 Swift 语法对范围没有任何作用。

Range 分为 RangeCountableRangeClosedRangeCountableClosedRange,在考虑使用范围时现在可能发生的事情时,这确实有意义(尽管它几乎没有必要)。

但是:我有很多函数接受 Range<Int> 作为参数或返回 Range<Int>。问题是:例如,我通过0..<50...4 调用这些函数(因为它有时在语义上更具表现力)。当然,我可以简单地调整这些类型的东西。但是为什么所有这些范围类型都没有一个通用接口呢?我必须为这些范围类型中的每一个重载每个函数,并且它每次都会执行完全相同的操作。

在 Swift 3 中使用范围是否有任何最佳实践?

【问题讨论】:

    标签: swift swift3


    【解决方案1】:

    封闭范围运算符

    封闭范围运算符(a...b) 定义从ab 的范围,并包括值aba 的值不能大于b

    当迭代一个您希望使用所有值的范围时,封闭范围运算符很有用,例如 for-in 循环:

    for index in 1...5 {
        print("\(index) times 5 is \(index * 5)")
    }
    // 1 times 5 is 5
    // 2 times 5 is 10
    // 3 times 5 is 15
    // 4 times 5 is 20
    // 5 times 5 is 25
    

    半开范围运算符

    半开范围运算符(a..<b) 定义了从ab 的范围,但不包括b。之所以说它是半开的,是因为它包含了它的第一个值,而不是它的最终值。与封闭范围运算符一样,a 的值不得大于b。如果a 的值等于b,则结果范围将为空。

    当您使用从零开始的列表(例如数组)时,半开范围特别有用,在这种情况下,最多可以计算(但不包括)列表的长度:

    let names = ["Anna", "Alex", "Brian", "Jack"]
    let count = names.count
    for i in 0..<count {
        print("Person \(i + 1) is called \(names[i])")
    }
    // Person 1 is called Anna
    // Person 2 is called Alex
    // Person 3 is called Brian
    // Person 4 is called Jack
    

    请注意,该数组包含四个项目,但0..&lt;count 只计算到​​3(数组中最后一项的索引),因为它是一个半开范围。

    封闭范围:a...b

    let myRange = 1...3
    let myArray = ["a", "b", "c", "d", "e"]
    myArray[myRange] // ["b", "c", "d"]
    

    半开范围:a..&lt;b

    let myRange = 1..<3
    let myArray = ["a", "b", "c", "d", "e"]
    myArray[myRange] // ["b", "c"]
    

    这是一个真实的 SpriteKit 示例,我必须使用几乎所有 SpriteKit 项目中的 arc4Random 进行转换。 Random 通常处理范围。

    斯威夫特 2

    Tools.swift
    
    func randomInRange(_ range: Range<Int>) -> Int {
        let count = UInt32(range.upperBound - range.lowerBound)
        return  Int(arc4random_uniform(count)) + range.lowerBound
    }
    
    GameScene.swift
    
    let gap = CGFloat(randomInRange(StackGapMinWidth...maxGap))
    

    斯威夫特 3

    Tools.swift
    
    func randomInRange(range: ClosedRange<Int>) -> Int {
        let count = UInt32(range.upperBound - range.lowerBound)
        return  Int(arc4random_uniform(count)) + range.lowerBound
    }
    
    GameScene.swift
    
    let gap = CGFloat(randomInRange(range: StackGapMinWidth...maxGap))
    

    所以如果randomInRange()计算给定范围内的随机数,包括上限,那么它应该定义为ClosedRange&lt;Bound&gt;

    Migrating to Swift 3

    RangeClosedRange 不能被迭代(它们不再是集合),因为仅仅是 Comparable 的值不能递增。 CountableRangeCountableClosedRange 需要 Strideable 从它们的绑定中,它们符合 Collection 以便您可以迭代它们。

    【讨论】:

      【解决方案2】:

      其实很简单:

      Closed...Range 是通过使用三个点生成的:0...10。这包括下限和上限。相反的是一个非封闭范围,由0..&lt;10 生成,不包括上限。

      Countable...Range 是一个可以使用有符号整数跨越的类型范围,它由0...100..&lt;10 生成。这些类型符合Sequence 协议。

      几个例子:

      0..<10 // CountableRange
      0...Int.max // CountableClosedRange (this was not possible before Swift 3)
      
      "A"..<"A" // Range, empty
      "A"..."Z" // ClosedRange, because cannot stride through, only check if a character is in the bounds
      

      您可能应该让您的方法接受一个通用的Collection/Sequence,具体取决于您的需要:

      func test<C: Collection where C.Iterator.Element == Int>(s: C) {
          print(s.first)
      }
      

      也许你可以展示你对Range&lt;Int&gt;的用途之一

      【讨论】:

      • 你答案中的最后一个代码 sn-p 是我要找的 ;) 谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-02
      相关资源
      最近更新 更多