Giá trị vô hướng bị ảnh hưởng sau khi đẩy, hoặc không phải (Raku)


12

Tôi gặp khó khăn khi hiểu và tại sao giá trị được giữ bởi một Scalarcontainer bị đẩy bị ảnh hưởng sau khi đẩy. Tôi sẽ cố gắng minh họa vấn đề mà tôi gặp phải trong một bối cảnh phức tạp hơn trong hai ví dụ cách điệu.

* Ví dụ 1 * Trong ví dụ đầu tiên, vô hướng $iđược đẩy lên một mảng @bnhư là một phần của a List. Sau khi đẩy, giá trị được giữ bởi vô hướng được cập nhật rõ ràng trong các lần lặp lại sau của vòng lặp for bằng cách sử dụng $i++lệnh. Các cập nhật này có ảnh hưởng đến giá trị trong mảng @b: ở cuối vòng lặp for, @b[0;0]bằng 3và không còn 2.

my @b;
my $i=0;
for 1..3 -> $x {
  $i++;
  say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
  if $x == 2 {
     @b.push(($i,1));
     say 'Pushed $i   : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;
  }
}
say "Post for-loop";
say "Array       : ", @b;
say 'Pushed $i   : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;

Ví dụ đầu ra 1:

Loose var $i: Scalar|94884317665520 139900170768608
Loose var $i: Scalar|94884317665520 139900170768648
Pushed $i   : Scalar|94884317665520 139900170768648
Loose var $i: Scalar|94884317665520 139900170768688
Post for-loop
Array       : [(3 1)]
Pushed $i   : Scalar|94884317665520 139900170768688

* Ví dụ 2 * Trong ví dụ thứ hai, vô hướng $ilà biến vòng lặp. Mặc dù $iđược cập nhật sau khi nó đã được đẩy (nay ngầm chứ không phải là rõ ràng), giá trị của $itrong mảng @cnào không thay đổi sau khi đẩy; tức là sau vòng lặp for, nó vẫn còn 2, không 3.

my @c;
for 1..3 -> $i {
  say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
  if $i == 2 {
     @c.push(($i,1));
     say 'Pushed $i   : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;
  }
}
say "Post for-loop";
say "Array       : ", @c;
say 'Pushed $i   : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;;

Ví dụ đầu ra 2:

Loose var $i: Scalar|94289037186864 139683885277408
Loose var $i: Scalar|94289037186864 139683885277448
Pushed $i   : Scalar|94289037186864 139683885277448
Loose var $i: Scalar|94289037186864 139683885277488
Post for-loop
Array       : [(2 1)]
Pushed $i   : Scalar|94289037186864 139683885277448

Câu hỏi: Tại sao $i@btrong ví dụ 1 được cập nhật sau khi việc đẩy mạnh, trong khi $i@ctrong ví dụ 2 không?

chỉnh sửa : Theo nhận xét của @ timotimo, tôi đã bao gồm đầu ra của .WHEREcác ví dụ. Điều này cho thấy nhận dạng vô hướng (WHICH / logic) $ivẫn giữ nguyên, trong khi địa chỉ bộ nhớ của nó thay đổi thông qua các lần lặp khác nhau. Nhưng điều đó không giải thích được tại sao trong ví dụ 2, vô hướng đẩy vẫn được gắn với cùng một danh tính WHICH kết hợp với một địa chỉ cũ ("448).


2
tôi có thể cho bạn câu trả lời tại sao WHICH dường như giữ nguyên; nhìn vào cách thực hiện: github.com/rakudo/rakudo/blob/master/src/core.c/Scalar.pm6#L8 - nó chỉ phụ thuộc vào bộ mô tả được sử dụng, một đối tượng nhỏ chứa những thứ như tên của biến và ràng buộc kiểu. nếu bạn sử dụng .WHEREthay vì .WHICHbạn có thể thấy rằng vô hướng thực sự là một đối tượng khác nhau mỗi lần xung quanh vòng lặp. Điều đó xảy ra vì các khối nhọn được "gọi" và chữ ký bị "ràng buộc" trên mỗi cuộc gọi.
timotimo

@raiph Trong vòng lặp, Ví dụ 1 hiển thị cùng một mẫu với Ví dụ 2: cả hai đều có địa chỉ thay đổi được báo cáo bởi .WHERE, đang nói, tôi đồng ý. Nhưng bản thân nó không giải thích được tại sao Ví dụ 2 lại có một kết thúc khác so với Ví dụ 1.
mờ

Câu trả lời:


5

Một giá trị vô hướng chỉ là một container. Bạn có thể nghĩ về chúng như một loại con trỏ thông minh, hơn là một giá trị nguyên thủy.

Nếu bạn làm một bài tập

$foo = "something"; #or
$bar++;

bạn đang thay đổi giá trị vô hướng, container vẫn giữ nguyên.

Xem xét

my @b; 
my $i=0; 
for 1..5 -> $x { 
  $i++; 
  @b.push(($i<>,1)); # decontainerize $i and use the bare value
} 
say @b;

my @b; 
my $i=0; 
for 1..5 -> $x { 
  $i := $i + 1;  # replaces the container with value / change value
  @b.push(($i,1)); 
} 
say @b;

Cả hai đều hoạt động như mong đợi. Nhưng: Trong cả hai trường hợp, điều trong danh sách không thể thay đổi được nữa, vì không có container.

@b[4;0] = 99; 

do đó sẽ chết. Vậy chỉ cần sử dụng biến vòng lặp, phải không?

Không.

for 1..5 -> $x { 
  @b.push(($x,1)); # 
} 
@b[4;0] = 99; #dies

ngay cả khi chúng ta lặp đi lặp lại một danh sách những thứ có thể thay đổi.

my $one = 1;
my $two = 2;
my $three = 3;
my $four = 4;
my $five = 5;

for ($one, $two, $three, $four, $five) -> $x { 
  @b.push(($x,1)); 
} 
@b[4;0] = 99; #dies

Vì vậy, không có bí danh nào xảy ra ở đây, thay vào đó, biến vòng lặp luôn là cùng một thùng chứa và được gán các giá trị đến từ các thùng chứa khác.

Chúng tôi có thể làm điều này mặc dù.

for ($one, $two, $three, $four, $five) <-> $x { 
  @b.push(($x,1)); 
} 
@b[4;0] = 99; # works

for ($one, $two, $three, $four, $five) -> $x is rw { 
  @b.push(($x,1)); 
} 
@b[4;0] = 99; # works too

Một cách để làm cho "thứ" có thể thay đổi là sử dụng một biến trung gian.

for 1..5 -> $x { 
  my $j = $x;
  @b.push(($j,1)); # a new container 
} 
@b[4;0] = 99;

hoạt động tốt Hoặc ngắn hơn và nhiều hơn trong bối cảnh ban đầu

my @b; 
my $i=0; 
for 1..5 -> $x { 
  $i++; 
  @b.push((my $ = $i, 1)); # a new anonymous container
} 
@b[4;0] = 99;
say @b; # [(1 1) (2 1) (3 1) (4 1) (99 1)]

Xem thêm:

https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/lingu/containers


1
Thay vì ($x,1), bạn cũng có thể làm điều [$x,1]đó sẽ tạo ra một container mới (cũng cho 1, BTW)
Elizabeth Mattijsen

@ElizabethMattijsen Nhưng sau đó, đó là Mảng "nâng" có?
Holli

Không chắc ý của bạn là gì khi "nâng", nhưng nếu bạn chứa các giá trị khi tạo, thì có.
Elizabeth Mattijsen

@Holli Cảm ơn bạn đã trả lời. Tôi không chắc chắn nếu nó giải quyết câu hỏi mặc dù. Câu trả lời của bạn tập trung vào tính biến đổi của container, điều mà tôi nghĩ là tôi hiểu. Điều tôi không hiểu là tại sao trong ví dụ đầu tiên, container được đẩy $ i - hoặc tốt hơn: giá trị của nó - được cập nhật sau khi đẩy, trong khi trong ví dụ thứ hai, giá trị của container được đẩy vẫn được gắn tĩnh với giá trị tại thời điểm này của đẩy. Ví dụ đầu tiên có ý nghĩa với tôi (container là con trỏ tới Intđối tượng -> Intđược thay thế trong vòng lặp for -> điểm chứa thành mới Int), nhưng lần thứ hai thì không.
ozzy

@Holli Tôi sẽ cố gắng làm rõ câu hỏi.
mờ

3

Sau khi chơi và suy nghĩ về câu hỏi trên của tôi một thời gian, tôi sẽ đặt câu trả lời ... Đó là phỏng đoán thuần túy của tôi, vì vậy xin vui lòng nói rằng nó không có ý nghĩa nếu nó là, và nếu bạn tình cờ biết, tại sao...

Trong ví dụ đầu tiên, $iđược định nghĩa bên ngoài phạm vi từ vựng của vòng lặp for. Do đó, $itồn tại độc lập với vòng lặp và lặp lại của nó. Khi $iđược tham chiếu từ bên trong vòng lặp, chỉ có một $icái có thể bị ảnh hưởng. Chính điều này $iđã bị đẩy vào@b và có nội dung của nó được sửa đổi sau đó trong vòng lặp.

Trong ví dụ thứ hai, $iđược định nghĩa bên trong phạm vi từ vựng của vòng lặp for. Như @timotimo đã chỉ ra, khối nhọn được gọi cho mỗi lần lặp, giống như một chương trình con; $ido đó được khai báo mới cho mỗi lần lặp và nằm trong phạm vi khối tương ứng. Khi $iđược tham chiếu bên trong vòng lặp, tham chiếu là đặc thù của khối lặp $i, thường sẽ không còn tồn tại khi vòng lặp tương ứng kết thúc. Nhưng bởi vì tại một thời điểm nào đó $iđược đẩy tới @c, tham chiếu đến $igiá trị giữ riêng cho khối lặp 2không thể bị xóa bởi trình thu gom rác sau khi chấm dứt lặp lại. Nó sẽ tồn tại ... nhưng vẫn khác với các $ilần lặp lại sau.


@raiph Cảm ơn. Tôi sẽ làm việc đó. Có lẽ ai đó có cái nhìn sâu sắc hơn bản thân tôi có thể (tái) cụm từ trả lời đúng. Dù sao tôi cũng sẽ không chấp nhận câu trả lời của mình là chính xác cho đến khi nó được xác nhận (hoặc cải thiện) bởi những người biết (chứ không phải đoán, như tôi).
ozzy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.