{"record":{"id":"af91e22c67a9f5e6","repo":"krahets/hello-algo","slug":"error-af91e2","errorCode":null,"errorMessage":"佇列為空","messagePattern":"佇列為空","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"zh-hant/codes/zig/chapter_stack_and_queue/array_queue.zig","lineNumber":77,"sourceCode":"            // 透過取餘操作實現 rear 越過陣列尾部後回到頭部\n            var rear = (self.front + self.queSize) % self.capacity();\n            // 在尾節點後新增 num\n            self.nums[rear] = num;\n            self.queSize += 1;\n        } \n\n        // 出列\n        pub fn pop(self: *Self) T {\n            var num = self.peek();\n            // 佇列首指標向後移動一位，若越過尾部，則返回到陣列頭部\n            self.front = (self.front + 1) % self.capacity();\n            self.queSize -= 1;\n            return num;\n        } \n\n        // 訪問佇列首元素\n        pub fn peek(self: *Self) T {\n            if (self.isEmpty()) @panic(\"佇列為空\");\n            return self.nums[self.front];\n        } \n\n        // 返回陣列\n        pub fn toArray(self: *Self) ![]T {\n            // 僅轉換有效長度範圍內的串列元素\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            var j: usize = self.front;\n            while (i < self.size()) : ({ i += 1; j += 1; }) {\n                res[i] = self.nums[j % self.capacity()];\n            }\n            return res;\n        }\n    };\n}\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/zh-hant/codes/zig/chapter_stack_and_queue/array_queue.zig#L59-L95","documentation":"Unrecoverable Zig @panic from peek() on the circular array queue. Guard `if (self.isEmpty()) @panic(\"佇列為空\")` runs before `return self.nums[self.front]`, so it prevents reading an undefined slot in the backing array. The queue treats peeking the head of an empty queue as a programming error.","triggerScenarios":"Call peek() (directly or via pop(), which calls peek() internally) on an ArrayQueue with queSize == 0 — freshly constructed, or after every element has been popped. Because pop() delegates to peek(), popping an empty queue surfaces this same panic rather than pop's own message.","commonSituations":"Consumer loops that pop/peek without an isEmpty gate; polling a queue before the first enqueue; round-robin schedulers that peek the head before any task is queued.","solutions":["Gate every peek()/pop() on `if (!q.isEmpty())` (or `q.size() > 0`).","Restructure the consumer to loop `while (!q.isEmpty()) { ... q.pop(); }` so no peek occurs at size 0.","Wrap the queue with a peek()-returning-?T adapter if empty-head inspection is legitimate."],"exampleFix":"// before\nvar n = q.pop();      // pop() internally peeks -> panic\n// after\nif (q.isEmpty()) return null;\nvar n = q.pop();","handlingStrategy":"validation","validationCode":"// call BEFORE peek()/pop()  (pop() delegates to peek())\nif (q.isEmpty()) return null;\nvar n = q.pop();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember pop() calls peek() internally — gate pop() too, not just peek().","Consume with `while (!q.isEmpty())` so no peek runs at size 0.","Polling loops must wait for the first enqueue before any peek."],"tags":["zig","queue","peek","circular-buffer","data-structure","empty-state"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}