7.4 – Iterators with Complex State(Lặp phức tạp)


Thông thường, một trình lặp cần giữ nhiều trạng thái hơn là phù hợp với một trạng thái bất biến duy nhất và một biến điều khiển. Giải pháp đơn giản nhất là sử dụng bao đóng. Một giải pháp thay thế là đóng gói tất cả những gì nó cần vào một bảng và sử dụng bảng này làm trạng thái bất biến cho lần lặp. Sử dụng một bảng, một trình vòng lặp có thể giữ nhiều dữ liệu mà nó cần dọc theo vòng lặp. Hơn nữa, nó có thể thay đổi dữ liệu đó khi nó diễn ra. Mặc dù trạng thái luôn là cùng một bảng (và do đó bất biến), nội dung bảng thay đổi dọc theo vòng lặp. Bởi vì các trình vòng lặp như vậy có tất cả dữ liệu của chúng ở trạng thái, chúng thường loại bỏ đối số thứ hai được cung cấp bởi biến chung cho (biến trình lặp).

Ví dụ về kỹ thuật này, chúng tôi sẽ viết lại các từ khóa của trình lặp, từ này sẽ duyệt qua tất cả các từ từ tệp đầu vào hiện tại. Lần này, chúng tôi sẽ giữ trạng thái của nó bằng cách sử dụng một bảng có hai trường, dòng và vị trí.

Hàm bắt đầu lặp rất đơn giản. Nó phải trả về hàm vòng lặp và trạng thái ban đầu:

local iterator   -- to be defined later Sẽ được định nghĩa sau
    
    function allwords ()
      local state = {line = io.read(), pos = 1}
      return iterator, state
    end

Hàm vòng lặp thực hiện công việc thực sự:

 function iterator (state)
      while state.line do        -- repeat while there are lines (Lặp khi có dòng)
        -- search for next word (Tìm kiếm từ tiếp theo)
        local s, e = string.find(state.line, "%w+", state.pos)
        if s then                -- found a word?(Nếu tìm thấy từ)
          -- update next position (after this word) --Cập nhật vị trí tiếp theo(sau từ này)
          state.pos = e + 1
          return string.sub(state.line, s, e)
        else    -- word not found Không tìm thấy từ thì
          state.line = io.read() -- try next line... thử dòng tiếp theo
          state.pos = 1          -- ... from first position từ vị trí đầu tiên
        end
      end
      return nil                 -- no more lines: end loop Nếu ko còn dòng nào nữa thì kết thúc vòng lặp
    end

Bất cứ khi nào có thể, bạn nên cố gắng viết các trình vòng lặp không trạng thái, những trình vòng lặp giữ tất cả trạng thái của chúng trong biến for. Với chúng, bạn không tạo các đối tượng mới khi bắt đầu một vòng lặp. Nếu bạn không thể phù hợp với lần lặp lại của mình vào mô hình đó, thì bạn nên thử các lần đóng. Bên cạnh việc thanh lịch hơn, thông thường một bao đóng còn hiệu quả hơn một trình vòng lặp sử dụng các bảng: Thứ nhất, việc tạo một bao đóng sẽ rẻ hơn một bảng; thứ hai, quyền truy cập vào các giá trị tăng nhanh hơn quyền truy cập vào các trường bảng. Sau đó, chúng ta sẽ thấy một cách khác để viết trình vòng lặp, với các coroutines. Đây là giải pháp mạnh mẽ nhất, nhưng đắt hơn một chút.

Leave a comment