Что такое "интервалы" в быстрых диапазонах?

Я знаю, что существует 3 типа диапазонов: Range, Strides и Intervals.

var closed:ClosedInterval = 1.2...5.0

var half_open:HalfOpenInterval = 1.2..<5.0

Каковы интервалы в быстром? и какой пример их использования?

http://en.wikipedia.org/wiki/Interval_(mathematics)

EDIT: Вот что отмечает релиз бета-версии 5 xcode 6:

• Интервалы по сравнению со сравнимыми значениями, которые могут эффективно проверять сдерживание. Интервалы используется для сопоставления шаблонов в операторах switch и оператором ~ =.

Ответ 1

Начиная с Swift 3 (в настоящее время в бета-версии с бета-версией Xcode 8, а также в сообществе Swift с открытым исходным кодом), типов Interval больше нет. Теперь семейство типов Range<T> включает функциональность как прежнего диапазона, так и интервальных типов и дополнительно соответствует новой модели для типов и индексов > .


В Swift 2.x и старше... Диапазоны для итерации, а интервалы - для соответствия шаблонов.

func testNum(num: Int) {
    let interval: HalfOpenInterval = 0..<10
    let range = 10..<20
    switch num {
    case interval:    // this works
        break
    case range:       // error "does not conform to protocol IntervalType"
        break
    default:
        break
    }
}

Тип A Range оптимизирован для генерации значений, которые увеличиваются по диапазону, и работает с типами, которые могут быть подсчитаны и увеличены.

Тип Interval оптимизирован для проверки того, находится ли заданное значение внутри интервала. Он работает с типами, которые необязательно требуют представления об увеличении и обеспечивают операции, такие как зажим одного диапазона в другой (например, (0..<10).clamp(5..<15) yields 5..<10), которые полезны для комплексного сопоставления шаблонов.

Так как операторы ..< и ... имеют две формы: один, который возвращает Range, и тот, который возвращает вывод типа Interval, автоматически использует правильный, основанный на контексте. Итак, если вы пишете 0..<10 в метке case оператора switch, Swift автоматически создает HalfOpenInterval, потому что для оператора switch требуется тип Interval.

Оператор ~= - это способ сделать один тест на интервале без инструкции switch. Запись interval ~= value эквивалентна interval.contains(value).


Стоит отметить, что вы можете узнать многие из этих вещей, взглянув на стандартный интерфейс библиотеки и свои комментарии: напишите имя типа, например HalfOpenInterval, на игровой площадке, затем нажмите "Command", чтобы перейти к его определению.

Ответ 2

Я подумал, что это так же хорошо, как и любой другой, чтобы оставить эту работу.

ОБНОВЛЕНИЕ: Я переделал это в своей серии "Swiftwater" (ссылка на запись серии на моем веб-сайте).

Так как Apple сделала такую ​​ужасную работу по описанию диапазонов и интервалов, я работаю через них на большой толстой игровой площадке (это как я делаю это). Я решил, что оставлю место на этой площадке в разделе.

Это также отличный способ получить исправления и экспертный обзор, поскольку я бы скорее понял вещи и делал их правильно, чем быть каким-то "ботёром-богом". Я часто ошибаюсь и делаю плохие предположения. Для этого отлично подходит экспертная оценка.

Кроме того, я считаю это публичной услугой, так как есть несколько вещей, которые выродки больше, чем рассказывать другим вундеркиндам, что они ошибаются. Нет, не благодари меня. Я получу награду на Небесах.

В любом случае, вот площадка на сегодняшний день. Все дело в том, чтобы уточнить их. В последующие дни я просто вставлю последующие части игровой площадки.

Обратите внимание на строку Intervals. Я собираюсь с ними немного пообщаться.

Я также попытаюсь создать классы, которые могут быть увеличены, и посмотреть, можно ли их использовать как значения диапазона.

ОБНОВЛЕНИЕ: Теперь я прошел базовое использование. Кажется, что многосимвольные интервалы строк находятся в области undefined. Я подниму вопрос RADAR на него и посмотрю, что Apple должна сказать.

UPDATE 2: Этот ответ охватывает нечетность String Interval.

UPDATE 3: Я обновил его для Swift 3.

UPDATE 4: Я обновил его для Swift 4. Мне все еще нужно больше тестировать, но я думаю, что все в порядке.

Вам следует открыть редактор ассистентов (Консоль), чтобы вы могли видеть результаты всех операторов print() (они не всегда отображаются в канавках для циклов).

// PART 1: SPECIFYING RANGES AND INTERVALS
// 1.1: RANGES

// First, we look at the Range type. Ranges are designed for incrementing. They have to be scalar (incrementable, usually, integers).
// Ranges always represent internally as min..<max When you do an inclusive range, it will represent internally as min..<max+1
let range1:CountableRange<Int>          = 0..<10    /* This contains 0,1,2,3,4,5,6,7,8,9 */
let range2:CountableRange               = 0..<10    /* This also contains 0,1,2,3,4,5,6,7,8,9 */
let range3                              = 0..<10    /* This also contains 0,1,2,3,4,5,6,7,8,9 */
let range4:CountableClosedRange<Int>    = 0...9     /* This also contains 0,1,2,3,4,5,6,7,8,9 */
let range5:CountableClosedRange         = 0...9     /* This also contains 0,1,2,3,4,5,6,7,8,9 */
let range6                              = 0...9     /* This also contains 0,1,2,3,4,5,6,7,8,9 */
// let range7:Range<Float>             = 0..<10    /* This is an error. Floats can't be incremented. */
// let range8:Range                    = 0.0...9.0 /* This is also an error. */
// let range9:Range<String>            = "0"..."9" /* This is an error. Even though these are strings in sequence, they can't be incremented. */

// 1.2: INTERVALS

// Next, let look at the Interval type. Intervals represent spreads of values, and can be non-integer types.

// 1.2.1: TYPES OF INTERVALS

// 1.2.1.1: CLOSED

// Closed intervals
let closed1:ClosedRange<Int>                     = 1...5         /* This represents 1,2,3,4,5 */
let closed2:ClosedRange                          = 3...7         /* This represents 3,4,5,6,7 */
// let closed3:ClosedInterval                          = 3..<8         /* This is an error. You can't specify a closed interval with an open operator. */

let closed4                                         = 3...7         /* This is not an Interval. It is a Range. */
let closed5                                         = 3..<8         /* This is not an Interval. It is a Range. */

let closed6Float:ClosedRange<Float>              = 2...9         /* This represents 2.0 -> 9.0 as a continuous range. */
let closed7Double                                   = 2.0...9.0     /* This represents 2.0 -> 9.0 as a continuous range. Specifying as a Double makes it an Interval.  */

// String Intervals
// These are odd. Looks like it is using the ASCII values. I should experiment with Unicode, and see where we go...
let aThroughFClosed:ClosedRange<String>          = "A"..."F"
let dThroughQClosed:ClosedRange                  = "D"..."Q"
let mThroughSClosed:ClosedRange                  = "M"..."S"
let tThroughWClosed:ClosedRange                  = "T"..."W"
let whiskeyTangoFoxtrot1                            = "QED"..."WTF" /* Not sure what will happen when I start working with this... */

// 1.2.1.2: HALF-OPEN

// Half-open intervals can only be open in the last value. The first value is inclusive.
let afopen1:Range<Int>                   = 5..<10        /* This represents 5,6,7,8,9 */
let afopen2:Range<Int>                   = 7..<20        /* This represents 7,8,9,10,11,12,13,14,15,16,17,18,19 */
let afopenFloat1:Range<Float>            = 2..<9         /* This represents 2.0 < 9.0 as a continuous range. */
let afopenFloat2:Range<Float>            = 7..<13        /* This represents 7.0 < 13.0 as a continuous range. */
// let afopen3:HalfOpenInterval<Int>                   = 5>..10        /* This is an error. You can't have half-open intervals open on the bottom. */
// let afopenFloat3:HalfOpenInterval<Float>            = 2...9         /* This is an error. You can't specify a half open as a closed. */

let aThroughHHalfOpen:Range<String>      = "A"..<"H"
let dThroughRHalfOpen:Range              = "D"..<"R"
let mThroughTHalfOpen:Range              = "M"..<"T"
let tThroughXHalfOpen:Range              = "T"..<"X"
let whiskeyTangoFoxtrot2                            = "QED"..<"WTF"

// 1.2.2: CLAMPING

// Clamping is basically the same as a set intersect. It selects the highest low value as the start, and the lowest high value as the end.
// You can clamp intervals, but not ranges.
let clampedValue1                                   = closed2.clamped ( to: closed1 )     /* This represents 3,4,5 */
let clampedValue2                                   = afopen2.clamped ( to: afopen1 )     /* This represents 7,8,9 */
// let clampedValue3                                   = closed2.clamped ( to: afopen1 )  /* This is an error. You can't mix interval types. */
// let clampedValue4                                   = afopenFloat2.clamped ( to: afopen1 )   /* This is an error. You can't clamp mixed types. */
// let clampedValue5                                   = closed4.clamped ( to: closed1 )  /* This is an error. Ranges can't clamp. */

let clampedString1 = dThroughQClosed.clamped ( to: aThroughFClosed )  /* This represents "D"..."F" */
let clampedString2 = aThroughFClosed.clamped ( to: dThroughQClosed )  /* This represents "D"..."F" */
let clampedString3 = mThroughSClosed.clamped ( to: dThroughQClosed )  /* This represents "M"..."Q" */
let clampedString4 = tThroughWClosed.clamped ( to: dThroughQClosed )  /* This represents "Q"..."Q" */
let clampedString5 = tThroughWClosed.clamped ( to: aThroughFClosed )  /* This represents "F"..."F" */

let clampedString6 = dThroughRHalfOpen.clamped ( to: aThroughHHalfOpen )  /* This represents "D"..<"G" */
let clampedString7 = aThroughHHalfOpen.clamped ( to: dThroughRHalfOpen )  /* This represents "D"..<"H" */
let clampedString8 = mThroughTHalfOpen.clamped ( to: dThroughRHalfOpen )  /* This represents "M"..<"R" */
let clampedString9 = tThroughXHalfOpen.clamped ( to: dThroughRHalfOpen )  /* This represents "R"..<"R" */
let clampedString0 = tThroughXHalfOpen.clamped ( to: aThroughHHalfOpen )  /* This represents "H"..<"H" (Not exactly sure why) */

// PART 2: USING RANGES AND INTERVALS

// 2.1 USING RANGES

// 2.1.1 RANGES AS LOOP ITERATORS

// The main use for ranges is cheap iterators for loops. They are easy to specify, and easy to use.

// A standard iterator
for i in range1 { print ( "Loop Iteration \(i)" ) }

// You can use the wildcard if you don't care about the actual iterator value.
for _ in range1 { print ( "Another Loop Iteration." ) }

// 2.2: USING INTERVALS

// Intervals are used for purposes of comparison and value matching.

// 2.2.1: INTEGER INTERVALS

// This is an error. You can't iterate Intervals.
// for i in closed1 { print ( "Loop Iteration \(i)" ) }

// 2.2.1.1 INTEGER INTERVALS AS SWITCH TESTS

// Use Intervals in switch statements to specify a range of possible values (a "catchbasket").
var testValue1 = 1

switch ( testValue1 )
{
    // This is an error. You can't match against Ranges.
    //    case closed4:
    //        print ( "In range!" )
    // This is an error. The Interval is a Double, but the test is an Int.
    //    case closed7Double:
    //        print ( "In closed7Double" )

case closed1:
    print ( "In closed1." )   /* This will catch the value. */

default:
    print ( "In catchall." )
}

switch ( testValue1 )   /* This will test against the interval of 3 -> 5 */
{
case clampedValue1:
    print ( "In clampedValue1." )

default:
    print ( "In catchall." )  /* Since it is not in the clamped interval, we fall into the catchall. */
}

// We try it with 3 as the value.
testValue1 = 3

switch ( testValue1 )
{
case closed1:
    print ( "In closed1." )   /* This will catch the value again. */

default:
    print ( "In catchall." )
}

switch ( testValue1 )
{
case clampedValue1:
    print ( "In clampedValue1." )   /* Now that the test value is in the interval window, we catch it here. */

default:
    print ( "In catchall." )
}

// This is a logical error (but not flagged by the compiler, so it counts as a "gotcha"). The two intervals have overlapping ranges.
// You are allowed to specify intervals that overlap, but only the first "hit" will count.

switch ( testValue1 )
{
case closed1:   /* This will catch all numbers between 1 and 5. */
    print ( "In closed1." )   /* This will catch the value, even though it also falls into the next one. */

case clampedValue1: /* This will not catch any numbers, as the interval is 3,4,5. */
    print ( "In clampedValue1." )

default:
    print ( "In catchall." )
}

// If we switch the two tests, then the clampedValue1 test is the hit.

switch ( testValue1 )
{
case clampedValue1:
    print ( "In clampedValue1." )   /* This will catch the value, even though it also falls into the next one. */

case closed1:
    print ( "In closed1." )

default:
    print ( "In catchall." )
}

// However, in this one, the second test will hit, because 1 is not in the first interval.
testValue1 = 1

switch ( testValue1 )
{
case clampedValue1:
    print ( "In clampedValue1." )

case closed1:
    print ( "In closed1." )   /* You sunk my battleship! */

default:
    print ( "In catchall." )
}

// 2.2.1.2 INTEGER INTERVALS AS BOOLEAN TESTS

// You test by using the Interval.contains() method.

if ( closed1.contains ( testValue1 ) )
{
    print ( "We gots us a match!" )
}

if ( !clampedValue1.contains ( testValue1 ) )
{
    print ( "We gots us a mismatch!" )
}

// 2.2.2: FLOATING POINT INTERVALS

// 2.2.2.1: FLOATING POINT INTERVALS AS SWITCH TESTS

var testValue2:Float = 2.0

switch ( testValue2 )
{
    // This is an error. You can't compare against other types.
    //    case closed1:
    //        print ( "In closed1." )

case afopenFloat1:  /* This will catch the value, as it is within the interval range. */
    print ( "In the range of 2..<9!" )

case afopenFloat2:
    print ( "In the range of 7..<13!" )

default:
    print ( "In catchall." )
}

testValue2 = 7.0

switch ( testValue2 )
{
case afopenFloat1: /* This will catch it, even though it is also in the next test range. */
    print ( "In the range of 2..<9!" )

case afopenFloat2:
    print ( "In the range of 7..<13!" )

default:
    print ( "In catchall." )
}

testValue2 = 8.999999   /* NOTE: Look at the displayed value. */

switch ( testValue2 )
{
case afopenFloat1: /* This will catch it. */
    print ( "In the range of 2..<9!" )

case afopenFloat2:
    print ( "In the range of 7..<13!" )

default:
    print ( "In catchall." )
}

// This illustrates a precision "gotcha." Note what happens when we add one more "9" to the end.
testValue2 = 8.9999999

switch ( testValue2 )
{
case afopenFloat1:
    print ( "In the range of 2..<9!" )

case afopenFloat2: /* This will catch it, even though the number is "less" than 9.0. */
    print ( "In the range of 7..<13!" )

default:
    print ( "In catchall." )
}

testValue2 = 9.0

switch ( testValue2 )
{
case afopenFloat1: /* This will not catch it, as the value needs to be LESS than 9.0 to match. */
    print ( "In the range of 2..<9!" )

case closed6Float:
    print ( "In the range of 2...9!" )  /* This will catch the value, as it is within the closed interval range. */

case afopenFloat2:
    print ( "In the range of 7..<13!" )

default:
    print ( "In catchall." )
}

testValue2 = 9.00001

switch ( testValue2 )
{
    // This is an error. The Interval is a ClosedInterval<Double>, but the test value is a Float
    //    case closed7Double:
    //        print ( "In closed7Double" )

case afopenFloat1: /* This will not catch it, as the value needs to be LESS than 9.0 to match. */
    print ( "In the range of 2..<9!" )

case closed6Float:
    print ( "In the range of 2...9!" )

case afopenFloat2:
    print ( "In the range of 7..<13!" ) /* This will catch the value, as it is within the interval range. */

default:
    print ( "In catchall." )
}

testValue2 = 1.0

switch ( testValue2 )
{
case afopenFloat1:
    print ( "In the range of 2..<9!" )

case afopenFloat2:
    print ( "In the range of 7..<13!" )

default: /* Since neither of the above intervals has this value, we get it. */
    print ( "In catchall." )
}

// Test with a Double (not a Float).
var testValue2Double:Double = 2.0

switch ( testValue2Double )
{
case closed7Double:  /* This will catch it. */
    print ( "In closed7Double" )

default:
    print ( "In catchall." )
}

testValue2Double = 1.999999999999999    /* There is enough precision to make this just less than 2.0 */

switch ( testValue2Double )
{
case closed7Double:
    print ( "In closed7Double" )

default:  /* This will catch it. */
    print ( "In catchall." )
}

// 2.2.2.2 FLOATING POINT INTERVALS AS BOOLEAN TESTS

testValue2 = 2.345

if ( afopenFloat1.contains ( testValue2 ) )
{
    print ( "We gots us a match!" )
}

if ( !afopenFloat2.contains ( testValue2 ) )
{
    print ( "We gots us a mismatch!" )
}

// 2.2.3: STRING INTERVALS

// String intervals are weird. Just sayin'...

// 2.2.3.1: STRING INTERVALS AS SWITCH TESTS

var testValue3:String = "B"

switch ( testValue3 )
{
case aThroughFClosed:   /* This will catch it. */
    print ( "In A...F." )

default:
    print ( "In catchall." )
}

// Looks like the test is only on the first letter.
testValue3 = "Badz-Maru"

switch ( testValue3 )
{
case aThroughFClosed:   /* This will catch it. */
    print ( "In A...F." )

default:
    print ( "In catchall." )
}

testValue3 = "\tBadz-Maru"   /* If we add a tab character to the start of the string, then the first test will fail. */

switch ( testValue3 )
{
case aThroughFClosed:
    print ( "In A...F." )

default:    /* This will catch it. */
    print ( "In catchall." )
}

// Now, we'll get really strange. Let look at our multi-character intervals...

testValue3 = "W"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:  /* This catches it. */
    print ( "WTF, dude?" )

default:
    print ( "In catchall." )
}

testValue3 = "T"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:  /* This catches it. */
    print ( "WTF, dude?" )

default:
    print ( "In catchall." )
}

testValue3 = "F"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:
    print ( "WTF, dude?" )

default: /* However, in this case, it falls through to default. */
    print ( "In catchall." )
}

testValue3 = "WT"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2: /* "WT" is caught. */
    print ( "WTF, dude?" )

default:
    print ( "In catchall." )
}

testValue3 = "WTF"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:
    print ( "WTF, dude?" )

default:    /* "WTF" is not caught. */
    print ( "In catchall." )
}

testValue3 = "QED"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:  /* "QED" is caught. */
    print ( "WTF, dude?" )

default:
    print ( "In catchall." )
}

testValue3 = "QTF"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:  /* "QTF" is caught. */
    print ( "WTF, dude?" )

default:
    print ( "In catchall." )
}

testValue3 = "QSF"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:  /* "QSF" is caught. */
    print ( "WTF, dude?" )

default:
    print ( "In catchall." )
}

testValue3 = "QAF"

switch ( testValue3 )
{
case whiskeyTangoFoxtrot2:
    print ( "WTF, dude?" )

default: /* QAF falls through. */
    print ( "In catchall." )
}

// Basically, I don't think we should use multi-character strings in intervals. The behavior seems undefined.

// PART 3: STRIDES

// Strides are sort of a Range. They are mostly used to iterate for loops. Use a stride to iterate in "jumps," or to iterate backwards (Ranges cannot be defined in reverse).

let randallFlagg:StrideTo<Int> = stride ( from: 0, to: 6, by: 3 )   /* StrideTo is a "half open" Range. It does not include the last value. */

for i1 in randallFlagg
{
    print ( "i1 is \(i1)" )
}

let aragorn:StrideThrough<Int> = stride ( from: 0, through: 6, by: 3 )  /* StrideThrough is a "closed" Range, which includes the last value. */

for i2 in aragorn
{
    print ( "i2 is \(i2)" )
}

// We can also use Strides to iterate backwards.

let frodo:StrideThrough<Int> = stride ( from: 6, through: 0, by: -3 )

for i3 in frodo
{
    print ( "i3 is \(i3)" )
}

// You can implicitly type the strides.
let bubbaThrough = stride ( from: 1, through: 5, by: 1 )

for bub in bubbaThrough
{
    print( "Bubba be \(bub)" )
}

let bubbaTo = stride ( from: 0, to: 5, by: 2 )

for bub in bubbaTo
{
    print( "Bubba be \(bub)" )
}

// Strides are often defined directly in the loop declarations.

for bub in stride ( from: 6, through: 0, by: -2 )
{
    print( "Bubba be \(bub)" )
}

// You can define a nonsensical stride, but it won't result in any loop executions.
let bubbaBad = stride ( from: 0, to: 5, by: -2 )

for bub in bubbaBad
{
    print( "Bubba be bad: \(bub)" )
}

// One advantage of Strides, is that you can increment in floating point steps.
let strideFloat:StrideTo<Float> = stride ( from: Float(0), to: 5, by: 2.1 )

for i4 in strideFloat
{
    print( "i4 is \(i4)" )
}

// These are the basics of the Range, Interval and Stride types, but there a lot more depth to this rabbit hole...

// PART 4: Range Generators (SequenceType)

// Range generators are basically iterators. Iterable classes can spit out a generator, which is basically a disposable iterator.

// This example came from here: http://schani.wordpress.com/2014/06/03/playing-with-swift/

let arr = [1, 2, 3]

for x in arr
{
    print ( x )
}

// Which is really...

var arrGen = arr.makeIterator()

while let x = arrGen.next()
{
    print ( x )
}

// Try the same thing with a dictionary.

let uncleBobIsCool = [ "A":1, "B":2, "C":3, "D":4, "E":5 ]

for x in uncleBobIsCool
{
    print ( x )
}

var dictGen = uncleBobIsCool.makeIterator()

while let x = dictGen.next()
{
    print ( x )
}

// This is an example I plucked from here: http://sketchytech.blogspot.com/2014/08/swift-adopt-sequence-protocol-and-use.html

// This shows how to create a simple struct-based iterator.

// SequenceType is a struct (not a class), and requires a GeneratorType-based struct as a typealias
struct MySequence:Sequence
{
    var x, y, length:Int    // These are the hypothetical struct data members.

    // The SequenceType protocol dictates that we have a generate() method that emits a GeneratorType-based struct.
    // Swift is kinda cool, in that you can define a typealias as a required prototype component.
    typealias GeneratorType = MyGenerator

    // This function instantiates a generator object, and returns that.
    // Since this is a struct, the object is a struct, and is returned by value.
    // That means that this object will not be affected by the iterator.
    func makeIterator() -> GeneratorType
    {
        // Length indicates how many iterations will be allowed.
        // The other two parameters are the starting values of the data members.
        return MyGenerator ( x:x, y:y, length:length )
    }

    mutating func next() -> GeneratorType.Element? {
        if length == 0 {
            return nil
        } else {
            length -= 1
            x += 1
            y += 1
            return ( x, y )
        }
    }
}

// This struct models one generator object.
// The generator is a "disposable" instance that is created by an instance of MySequence.
// The GeneratorType protocol requires a generic type, called "Element," which can be anything you want,
// and a "next()" method that returns one of the "Element" instances.
struct MyGenerator:IteratorProtocol
{
    var x, y, length:Int    // These are the values

    typealias Element = ( Int, Int )    // In the case of this example, "Element" is a tuple, containing x and y Int values.

    // This is the required next() method. Since this is a struct, we need the "mutating" keyword.
    mutating func next() -> Element?    // The return is optional, as we return nil when done.
    {
        // We just go for as many counts as "length" gave us, incrementing the values as we go.
        if length > 0
        {
            length -= 1
            x += 1
            y += 1
            return ( x, y )
        }
        else
        {
            return nil  // At the end, we return nil.
        }
    }
}

var seq = MySequence ( x:10, y:10, length:10 )

for point in seq
{
    print ( point )
}

// We can go again without a rewind.
// Note the data member values are at the old starting point.
// That because internally, a new generator is created.

for point in seq
{
    print ( point )
}

// Let create a new instance.
seq = MySequence ( x:10, y:10, length:10 )

// This is what going on inside.
// Note that we need a "var", as we are mutating the struct.
var seqGen = seq.makeIterator()

// Since we generated a new generator, we start from the beginning again.
while let x = seqGen.next()
{
    print ( x )
}

// Now, if we try to go again, we won't have any luck.
while let x = seqGen.next()
{
    print ( x )
}

// However, if we reset length in the generator, we can go again, continuing to increment the values.
seqGen.length = 10

while let x = seqGen.next()
{
    print ( x )
}

// Just to prove that the original instance remains untouched.
print ( "x: \( seq.x ), y: \( seq.y ), length: \( seq.length )" )

Что это сейчас. Я буду рассматривать некоторые из более продвинутых поведений этого материала самостоятельно, но я понял, что поставил здесь эту площадку, чтобы улучшить знания племени на этом материале.

Я действительно надеюсь, что Apple улучшит свои документы по этому поводу, таким образом, отменив мой ответ.