2015-04-02 17 views
5

Tôi đang cố gắng triển khai một ví dụ về SequenceType/GeneratorType và nhận được một lỗi không hoàn toàn hợp lý.Swift SequenceType không hoạt động

Dưới đây là các mã:

// 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)) 
    } 
} 

Khi tôi gọi đây (trong sân chơi) nó hoạt động hoàn toàn tốt:

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()!)") 

Cho đến nay rất tốt như vậy.

Tiếp theo là 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 
     } 
    } 

} 

Đó là những gì đang tạo ra một lỗi: 'Type RandomNumberSequence' does not conform to protocol 'SequenceType'. (Xcode đang hiển thị lỗi này ngay trên đó dòng đầu tiên của báo cáo kết quả khai struct RandomNumbersSequence:SequenceType.)

Tôi thực sự nghĩ logic của for vòng lặp của tôi có thể sai - có nghĩa là tôi sẽ không có được kết quả tôi thực sự muốn - nhưng bất kể, về mặt thỏa mãn giao thức SequenceType là cần thiết, tôi nghĩ rằng tôi đã nhận được nhiều điều đúng đắn. Vậy điều gì gây ra lỗi này?

+0

Chỉ cần kiểm tra - bạn đang cố gắng viết e một chuỗi phục vụ x số ngẫu nhiên? I E. nếu bạn tạo 'let seq = RandomNumbersSequence (maxNum: 5)', sau đó làm 'for i in seq {}' bạn sẽ nhận được 5 số ngẫu nhiên? –

Trả lời

7

Đây không phải là cách thức hoạt động của máy phát. Giả sử bạn muốn phục vụ một số các số ngẫu nhiên, bạn có ý tưởng đúng về việc lấy một tham số tối đa, nhưng bạn cũng cần lưu trữ nó trong bộ tạo, cộng với một số trạng thái cho nó ở đâu.

Ý tưởng với máy phát điện là nó lưu trữ trạng thái của nó và mỗi lần bạn gọi next() bạn trả về phần tử tiếp theo. Vì vậy, nếu bạn muốn tạo ra một hoạt động lên đến n số, bạn có thể làm một cái gì đó như sau:

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 
     } 
    } 
} 

Lưu ý, bạn không cần một vòng lặp for đây.Chỉ mỗi lần next() được gọi là, i được tăng lên, cho đến khi đạt đến mức tối đa, thì trình tạo sẽ bắt đầu quay trở lại nil.

Mục đích của SequenceType là để phục vụ lên máy phát điện tươi:

struct RandomNumberSequence: SequenceType { 
    let n: Int 
    init(count: Int) { self.n = count } 

    func generate() -> RandomNumberGenerator { 
     return RandomNumberGenerator(count: n) 
    } 
} 

Vì điều này, bây giờ bạn có thể sử dụng nó để tạo ra một chuỗi các số cố định của các số nguyên ngẫu nhiên:

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 

Tạo các máy phát trạng thái này là một vấn đề khá phổ biến, do đó thư viện chuẩn có cấu trúc trợ giúp, GeneratorOf, cho phép bạn bỏ qua việc định nghĩa chúng. Phải mất một đóng cửa mà mỗi lần nó được gọi là nên trả về giá trị tiếp theo để tạo ra:

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 
      } 
     } 
    } 
} 
+0

Đây phải là câu trả lời được chấp nhận. – nhgrif

+0

nhgrif ok, tôi sẽ hỏi bạn về điều đó. Nhưng sẽ làm. Cả hai đều đáng tin cậy. @ Airspeed - cảm ơn vì lời giải thích - nó rất kỹ lưỡng và tôi hoàn toàn hiểu nó ngay bây giờ. Cảm ơn bạn. – sirab333

1

Thông điệp lỗi mà bạn thấy:

'Type RandomNumberSequence' does not conform to protocol 'SequenceType'

Luôn có nghĩa là lớp học hoặc struct của bạn thiếu cái gì đó giao thức tuyên bố theo yêu cầu.

Trong trường hợp này, chúng tôi thiếu phương thức generate() -> Generator. "Nhưng, nó ở ngay đó!" bạn nói? Vâng, nó là, nhưng nó không biên dịch.

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

Vấn đề là, nếu bạn khởi tạo struct của bạn với numberOfRandomNumbers ít hơn hoặc bằng 0? Vòng lặp của bạn thực thi 0 lần và generate không thể trả về bất kỳ thứ gì.

Tôi không chắc chắn chính xác gì logic bạn đang cố gắng để làm trong vòng lặp này, nhưng chúng tôi có thể sửa chữa các lỗi biên dịch bằng cách đơn giản là một cách thêm một tuyên bố trở lại mà sẽ trả về một Generator:

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

Điều này sẽ không làm những gì bạn đang cố gắng hoàn thành. Đây không phải là cách máy phát điện được cho là hoạt động. Nhưng nó sẽ sửa chữa phương thức generate() -> Generator và cho phép cấu trúc của bạn bây giờ phù hợp với giao thức.

+0

Hmm, trông rất đẹp - nhưng nó vẫn không hoạt động. Tôi đã thực hiện thay đổi mà bạn đề nghị, nhưng bây giờ tôi nhận được điều này: 'Swift._Sequence_Type ... lưu ý: giao thức yêu cầu loại lồng nhau 'Generator' typealias Generator: GeneratorType'. Ngoài ra điều này: 'lưu ý: có thể dự định phù hợp 'Máy phát điện' không phù hợp với 'GeneratorType' typealias Generator = RandomNumberGenerator'. Rất lạ ... – sirab333

+0

Vâng, tôi nghĩ nó là một sân chơi. Nó có vẻ là ok khi chạy như một dự án Xcode ... vẫn đang kiểm tra ... – sirab333

+0

Vâng, def của nó. Sân chơi - hoạt động trong Xcode - BAO GIỜ ... Tôi đang nhận được một vòng lặp vô hạn - nó tiếp tục tạo ra các số ngẫu nhiên mãi mãi. Những gì tôi đang _trying_ để làm ở đây chỉ đơn giản là tạo ra một chuỗi X số ngẫu nhiên, nơi tôi có thể truyền giá trị cho X mỗi khi tôi tạo một chuỗi. Nhưng khi tôi gọi nó - như thế này: 'var randySequence = RandomNumbersSequence (maxNum: 10)', nó chỉ chạy và chạy và chạy ... Tôi nghĩ rằng vòng lặp 'for' của tôi sẽ giới hạn nó với bất kỳ số nào tôi truyền vào. Rõ ràng là tôi không hoàn toàn nhận được một cái gì đó về việc kinh doanh trình tự này. Bất kỳ ý tưởng? – sirab333

0

Với Swift 3, bạn có thể chọn một trong ba RandomNumbersSequence triển khai để giải quyết vấn đề của bạn.


1. Sử dụng một cấu trúc mà phù hợp với Sequence giao thức và một cấu trúc mà phù hợp với giao thức IteratorProtocol

Mã Sân chơi sau đây cho thấy làm thế nào để thực hiện một struct RandomNumbersSequence rằng phù hợp với Sequence và có sử dụng một cấu trúc RandomNumbersIterator mà phù hợp với IteratorProtocol giao thức:

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) 
    } 

} 

Cách sử dụng # 1:

for value in RandomNumbersSequence(maxNum: 3) { 
    print(value) 
} 

/* 
may print: 
5 
7 
3 
*/ 

Cách sử dụng # 2:

let randomArray = Array(RandomNumbersSequence(maxNum: 3)) 
print(randomArray) 

/* 
may print: [7, 6, 1] 
*/ 

Cách sử dụng # 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. Sử dụng một cấu trúc mà phù hợp với SequenceIteratorProtocol giao thức

Mã Sân chơi sau cho thấy cách triển khai RandomNumbersSequence struct đó phù hợp với SequenceIteratorProtocol giao thức:

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 
    } 

} 

Cách sử dụng # 1:

for value in RandomNumbersSequence(maxNum: 3) { 
    print(value) 
} 

/* 
may print: 
5 
7 
3 
*/ 

Cách sử dụng # 2:

let randomArray = Array(RandomNumbersSequence(maxNum: 3)) 
print(randomArray) 

/* 
may print: [7, 6, 1] 
*/ 

Cách sử dụng # 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.Sử dụng AnyIterator và một cấu trúc mà phù hợp với Sequence

Để thay thế cho việc thực hiện trước đó, bạn có thể sử dụng AnyIterator<T> như kiểu trả về của phương pháp makeIterator bên Sequence giao thức của bạn phù hợp với cấu trúc. Mã sân chơi sau đây cho thấy làm thế nào để thực hiện nó với RandomNumbersSequence struct của bạn:

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 
    } 

} 

Cách sử dụng # 1:

for value in RandomNumbersSequence(maxNum: 3) { 
    print(value) 
} 

/* 
may print: 
5 
7 
3 
*/ 

Cách sử dụng # 2:

let randomArray = Array(RandomNumbersSequence(maxNum: 3)) 
print(randomArray) 

/* 
may print: [7, 6, 1] 
*/ 

Cách sử dụng # 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 
Các vấn đề liên quan