Đánh giá TL; DR Defer $<nr>
cho đến sau khi đánh giá regex. @ JoKing ++ gợi ý một cách . Một cách khác là chỉ bọc thay thế bằng niềng răng ( {$<nr>}
).
Điều gì xảy ra khi mã gốc của bạn gọi subst
Trước khi Raku cố gắng gọi subst
thói quen, nó tập hợp một danh sách các đối số để truyền cho nó.
Có hai giá trị. Đầu tiên là một regex. Nó không chạy . Giá trị thứ hai là $<nr>
. Nó ước tính Nil
bởi vì, khi bắt đầu một chương trình, biến đối tượng khớp hiện tại bị ràng buộc với thứ gì đó tuyên bố giá trị của nó Nil
và mọi nỗ lực truy cập giá trị của khóa trong nó - $<nr>
- cũng trả về Nil
. Vì vậy, mọi thứ đã đi sai vào thời điểm này, trước khi subst
chạy.
Khi Raku đã tập hợp danh sách các đối số này, nó sẽ cố gắng gọi subst
. Nó thành công, và subst
chạy.
Để có được trận đấu tiếp theo, hãy subst
chạy regex. Điều này cập nhật biến đối tượng phù hợp hiện tại $/
. Nhưng đã quá muộn để tạo ra bất kỳ sự khác biệt nào đối với giá trị thay thế đã được chuyển qua subst
.
Với trận đấu trong tay, subst
tiếp theo xem xét đối số thay thế. Nó tìm thấy nó Nil
và hành động phù hợp.
Đối với cuộc gọi thứ hai của subst
, $<nr>
đã lấy giá trị từ cuộc gọi đầu tiên của subst
. Và như thế.
Hai cách để trì hoãn đánh giá $<nr>
@JoKing đề nghị xem xét sử dụng S///
. Cấu trúc này đánh giá regex (giữa cặp /
s đầu tiên) trước, sau đó thay thế (giữa cặp /
s cuối cùng ). (Nguyên tắc tương tự được áp dụng nếu bạn sử dụng các S
cú pháp hợp lệ khác như S[...] = ...
.)
Nếu bạn sử dụng subst
, như đã giải thích trong phần trước, Raku sẽ tập hợp danh sách đối số cho nó trước khi gọi nó. Nó tìm thấy một regex (cái mà nó không chạy) và một cái đóng (cái mà nó cũng không chạy). Sau đó, nó cố gắng gọi subst
với những đối số đó và thành công trong việc làm như vậy.
Tiếp theo, subst
bắt đầu chạy. Nó đã nhận được mã cho cả trận đấu (regex) và thay thế (đóng cửa).
Nó chạy regex như hoạt động phù hợp. Nếu regex trả về một kết quả khớp thì subst
chạy bao đóng và sử dụng giá trị mà nó trả về làm thay thế.
Do đó, vì chúng tôi đã chuyển từ chuyển $<nr>
thành giá trị trần, có nghĩa là nó bị đóng băng Nil
, chuyển sang đóng gói, trong đó hoãn lại đánh giá của nó cho đến khi $/
được đặt thành khớp với <nr>
mục nhập dân cư , chúng tôi đã giải quyết vấn đề.
Lưu ý rằng điều này chỉ hoạt động bởi vì bất kỳ ai được thiết kế / triển khai subst
đều thông minh / đủ tốt để cho phép cả đối số đối sánh và đối số là dạng Code
(một biểu thức chính thức cho kết quả khớp và đóng thông thường để thay thế) nếu người dùng muốn điều đó. Sau đó, nó chạy trận đấu trước và chỉ sau đó chạy kết thúc thay thế nếu nó được thông qua, sử dụng kết quả của cuộc gọi sau đó làm thay thế cuối cùng. Tương tự, S///
hoạt động vì điều đó đã được thiết kế để chỉ đánh giá sự thay thế sau lần đầu tiên nó đánh giá sự thay thế.