with while loop index for swift foreach generator sequence for-in-loop

while - Swift SequenceType no funciona



swift for each with index (3)

El mensaje de error que está viendo:

''Type RandomNumberSequence'' no se ajusta al protocolo ''SequenceType''

Siempre significa que a su clase o estructura le falta algo que el protocolo declara como requerido.

En este caso, nos falta el método generate() -> Generator . "¡Pero está justo allí!" ¿tu dices? Bueno, lo es, pero no está compilando.

func generate() -> Generator { for i in 1...numberOfRandomNumbers { var randNum = Generator() randNum.next() return randNum } }

El problema es, ¿qué sucede si inicializas tu estructura con numberOfRandomNumbers menor o igual que 0 ? Su ciclo se ejecuta cero veces y generate no puede devolver nada.

No estoy seguro exactamente qué lógica está tratando de hacer en este ciclo, pero podemos corregir los errores de compilación simplemente agregando una declaración de retorno que devolverá un Generator :

func generate() -> Generator { for i in 1...numberOfRandomNumbers { var randNum = Generator() randNum.next() return randNum } return Generator() }

Esto no hará lo que estás tratando de lograr. No es así como deben funcionar los generadores. Pero arreglará el método generate() -> Generator y permitirá que su estructura se conforme al protocolo.

Estoy tratando de implementar un ejemplo de SequenceType / GeneratorType y obtener un error que no tiene mucho sentido.

Aquí está el código:

// Here''s my GeneratorType - it creates a random-number Generator: struct RandomNumberGenerator:GeneratorType { typealias Element = Int mutating func next() -> Element? { return Int(arc4random_uniform(100)) } }

Cuando llamo esto (en Playgrounds) funciona perfectamente bien:

var randyNum = RandomNumberGenerator() randyNum.next() // this shows a valid random number in the Gutter // And calling it from within a println also works: println("randyNum = /(randyNum.next()!)")

Hasta ahora todo bien.

El siguiente es el SequenceType:

struct RandomNumbersSequence:SequenceType { typealias Generator = RandomNumberGenerator var numberOfRandomNumbers:Int init(maxNum:Int) { numberOfRandomNumbers = maxNum } func generate() -> Generator { for i in 1...numberOfRandomNumbers { var randNum = Generator() randNum.next() return randNum } } }

Eso es lo que genera un error: ''Type RandomNumberSequence'' does not conform to protocol ''SequenceType'' . (Xcode muestra este error en la primera línea de la declaración struct RandomNumbersSequence:SequenceType instrucción struct RandomNumbersSequence:SequenceType ).

De hecho, creo que la lógica de mi bucle for puede ser incorrecta, lo que significa que no obtendré los resultados que realmente quiero, pero a pesar de todo, en términos de satisfacer lo que exige el protocolo SequenceType , creo que entendí bien. Entonces, ¿qué está causando este error?


Esto no es exactamente cómo funcionan los generadores. Suponiendo que desea servir un número determinado de números aleatorios, tiene la idea correcta de tomar un máximo como parámetro, pero también debe almacenar eso en el generador, además de algún estado para el lugar en el que se encuentra.

La idea con un generador es que almacena su estado, y cada vez que llamas a next() devuelves el siguiente elemento. Entonces, si desea generar una carrera de hasta n números, podría hacer algo como lo siguiente:

struct RandomNumberGenerator: GeneratorType { let n: Int var i = 0 init(count: Int) { self.n = count } mutating func next() -> Int? { if i++ < n { return Int(arc4random_uniform(100)) } else { return nil } } }

Tenga en cuenta que no necesita un bucle for aquí. Cada vez que se llama a next() , i se incrementa, hasta que alcanza el máximo, entonces el generador comienza a devolver nil .

El objetivo de SequenceType es servir generadores nuevos:

struct RandomNumberSequence: SequenceType { let n: Int init(count: Int) { self.n = count } func generate() -> RandomNumberGenerator { return RandomNumberGenerator(count: n) } }

Dado esto, ahora puede usarlo para generar una secuencia de un número fijo de enteros aleatorios:

let seq = RandomNumberSequence(count: 3) for x in seq { // loops 3 times with x being a new random number each time } // every time you use seq, you get a new set of 3 numbers ",".join(map(seq,toString)) // prints 3 comma-separated random nums // but when you create a generator, it gets “used up” var gen = seq.generate() println(gen.next()) // prints a random number println(gen.next()) // prints another random number println(gen.next()) // prints the third println(gen.next()) // prints nil println(gen.next()) // and will keep printing nil gen = seq.generate() println(gen.next()) // will print the first of a new set of 3 numbers

La creación de estos generadores con estado es un problema bastante común, por lo que la biblioteca estándar tiene una estructura auxiliar, GeneratorOf , que le permite omitir la definición de ellos. Se necesita un cierre que cada vez que se llame debe devolver el siguiente valor para generar:

struct RandomNumbersSequence: SequenceType { let maxNum: Int init(maxNum: Int) { self.maxNum = maxNum } func generate() -> GeneratorOf<Int> { // counter to track how many have been generated var n = 0 return GeneratorOf { // the closure “captures” n if n++ < self.maxNum { return Int(arc4random_uniform(100)) } else { return nil } } } }


Con Swift 3, puede elegir una de las tres implementaciones de RandomNumbersSequence para resolver su problema.

1. Usar una estructura que se ajuste al protocolo de Sequence y una estructura que se ajuste al protocolo IteratorProtocol

El siguiente código de Playground muestra cómo implementar una estructura RandomNumbersSequence que se ajuste a Sequence y que utilice una estructura RandomNumbersIterator que se ajuste al protocolo IteratorProtocol :

import Darwin // required for arc4random_uniform struct RandomNumbersIterator: IteratorProtocol { let maxNum: Int var n = 0 init(maxNum: Int) { self.maxNum = maxNum } mutating func next() -> Int? { n += 1 return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil } } struct RandomNumbersSequence: Sequence { let maxNum: Int init(maxNum: Int) { self.maxNum = maxNum } func makeIterator() -> RandomNumbersIterator { return RandomNumbersIterator(maxNum: maxNum) } }

Uso # 1:

for value in RandomNumbersSequence(maxNum: 3) { print(value) } /* may print: 5 7 3 */

Uso # 2:

let randomArray = Array(RandomNumbersSequence(maxNum: 3)) print(randomArray) /* may print: [7, 6, 1] */

Uso # 3:

let randomSequence = RandomNumbersSequence(maxNum: 3) var randomGenerator = randomSequence.makeIterator() randomGenerator.next() // may return: 4 randomGenerator.next() // may return: 8 randomGenerator.next() // may return: 3 randomGenerator.next() // will return: nil

2. Usar una estructura que se ajuste a los protocolos Sequence y IteratorProtocol

El siguiente código de Playground muestra cómo implementar una estructura RandomNumbersSequence que se ajuste a los protocolos Sequence y IteratorProtocol :

import Darwin // required for arc4random_uniform struct RandomNumbersSequence: Sequence, IteratorProtocol { let maxNum: Int var n = 0 init(maxNum: Int) { self.maxNum = maxNum } mutating func next() -> Int? { n += 1 return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil } }

Uso # 1:

for value in RandomNumbersSequence(maxNum: 3) { print(value) } /* may print: 5 7 3 */

Uso # 2:

let randomArray = Array(RandomNumbersSequence(maxNum: 3)) print(randomArray) /* may print: [7, 6, 1] */

Uso # 3:

var randomSequence = RandomNumbersSequence(maxNum: 3) randomSequence.next() // may return: 4 randomSequence.next() // may return: 8 randomSequence.next() // may return: 3 randomSequence.next() // will return: nil

3. Usando AnyIterator y una estructura que se ajusta a Sequence

Como alternativa a la implementación anterior, puede utilizar AnyIterator<T> como el tipo de makeIterator método makeIterator dentro de su estructura de conformidad con el protocolo de Sequence . El siguiente código de Playground muestra cómo implementarlo con su estructura RandomNumbersSequence :

import Darwin // required for arc4random_uniform struct RandomNumbersSequence: Sequence { let maxNum: Int init(maxNum: Int) { self.maxNum = maxNum } func makeIterator() -> AnyIterator<Int> { var n = 0 let iterator: AnyIterator<Int> = AnyIterator { n += 1 return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil } return iterator } }

Uso # 1:

for value in RandomNumbersSequence(maxNum: 3) { print(value) } /* may print: 5 7 3 */

Uso # 2:

let randomArray = Array(RandomNumbersSequence(maxNum: 3)) print(randomArray) /* may print: [7, 6, 1] */

Uso # 3:

let randomSequence = RandomNumbersSequence(maxNum: 3) let randomGenerator = randomSequence.makeIterator() randomGenerator.next() // may return: 4 randomGenerator.next() // may return: 8 randomGenerator.next() // may return: 3 randomGenerator.next() // will return: nil