{"record":{"id":"13b90b6f34ee60e3","repo":"krahets/hello-algo","slug":"error-13b90b","errorCode":null,"errorMessage":"雙向佇列為空","messagePattern":"雙向佇列為空","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"zh-hant/codes/zig/chapter_stack_and_queue/linkedlist_deque.zig","lineNumber":100,"sourceCode":"                node.prev = self.rear;\n                self.rear = node;   // 更新尾節點\n            }\n            self.que_size += 1;      // 更新佇列長度\n        } \n\n        // 佇列首入列\n        pub fn pushFirst(self: *Self, num: T) !void {\n            try self.push(num, true);\n        } \n\n        // 佇列尾入列\n        pub fn pushLast(self: *Self, num: T) !void {\n            try self.push(num, false);\n        } \n        \n        // 出列操作\n        pub fn pop(self: *Self, is_front: bool) T {\n            if (self.isEmpty()) @panic(\"雙向佇列為空\");\n            var val: T = undefined;\n            // 佇列首出列操作\n            if (is_front) {\n                val = self.front.?.val;     // 暫存頭節點值\n                // 刪除頭節點\n                var fNext = self.front.?.next;\n                if (fNext != null) {\n                    fNext.?.prev = null;\n                    self.front.?.next = null;\n                }\n                self.front = fNext;         // 更新頭節點\n            // 佇列尾出列操作\n            } else {\n                val = self.rear.?.val;      // 暫存尾節點值\n                // 刪除尾節點\n                var rPrev = self.rear.?.prev;\n                if (rPrev != null) {\n                    rPrev.?.next = null;","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/zh-hant/codes/zig/chapter_stack_and_queue/linkedlist_deque.zig#L82-L118","documentation":"Unrecoverable Zig @panic from pop(is_front) on the linked-list deque. Guard `if (self.isEmpty()) @panic(\"雙向佇列為空\")` runs before reading `self.front.?.val`, protecting the optional unwrap. Popping an empty deque is treated as a logic error rather than a recoverable empty result.","triggerScenarios":"Call popFirst()/popLast() (both delegate to pop()) on an empty deque, or pop a deque that has been drained to size 0. Any pop issued after the last element was removed will trip it.","commonSituations":"Drain loops that pop one extra time; sliding-window / monotonic-deque algorithms that pop both ends and overshoot when the window is empty; producer/consumer where the consumer leads the producer.","solutions":["Gate every popFirst()/popLast() with `if (!dq.isEmpty())` or a `dq.size() > 0` check.","Bound drain loops on size() so they stop exactly when the deque empties.","Add a wrapper returning ?T if pop-on-empty is a legitimate control-flow signal in your code."],"exampleFix":"// before\nvar v = dq.popFirst();\n// after\nif (dq.isEmpty()) return null;\nvar v = dq.popFirst();","handlingStrategy":"validation","validationCode":"// call BEFORE popFirst()/popLast()\nif (dq.isEmpty()) return null;\nvar v = dq.popFirst();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate every pop on isEmpty()/size() before calling.","Bound drain loops on size() so they stop at exactly zero.","For sliding-window/monotonic-deque code, assert the deque is non-empty before each pop."],"tags":["zig","deque","data-structure","panic","empty-state"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}