Red语言foreach中的变量值

Variable value in foreach of Red language

我正在使用以下代码通过 foreach 循环将多个 GUI 元素添加到视图:

myRange: function [n][  ; to produce a vector of [1 2 3 4... n]
  vv: make vector! n 
  i: 1
  foreach j vv [
    vv/:i: i
    i: i + 1
    if i > n [break]]
  vv ]

view collect[ 
    foreach i myRange 10 [  
        print append "i in loop: " i
        keep [ t: text ]  keep append "message number: " i
        keep [field "entry"     button "Click" [t/text: "clicked"] return]
            ] ]

正在制作所有 GUI 元素。但是代码 append "message number: " i 在所有文本元素中显示 i 的值是 12345678910 而不是 1, 2, 3... 10 对于不同的文本元素。

此外,print append... 语句产生以下输出:

i in loop: 1
i in loop: 12
i in loop: 123
i in loop: 1234
i in loop: 12345
i in loop: 123456
i in loop: 1234567
i in loop: 12345678
i in loop: 123456789
i in loop: 12345678910

此外,单击任何按钮只会更改最后添加的文本元素的文本。

问题出在哪里,如何解决?感谢您的帮助。


编辑:似乎语言正在转换我的代码:

for i 1 10 1 [  
   print append "i in loop: " i  ]

至:

a_variable: "i in loop"
for i 1 10 1 [  
   print append a_variable i  ]

这不是我和(我认为)大多数用户想要的。在大多数语言中,字符串 "i in loop" 将被视为常量而不是转换为变量,因为用户没有指定它。恕我直言,如果不改变这些基本约定,其他语言的用户会更容易来到这里。

Rebol 和 Red 尽可能多地重用系列(例如字符串、块),如果您不通过 copymake 等重新初始化来告诉它们的话。所以您的问题应该会消失如果你写

append copy "message number: " i

每当您看到这样的内容时,就意味着您未能创建新系列并正在重复使用现有系列。

要解决这个问题,您需要使用 copy

创建一个新系列

例如

print append copy "i in loop: " i

Rebol3/ren-c 不再有此问题,因为源代码是不可变的,因此您会收到此类代码的错误消息。

正如其他答案所暗示的那样,您的消息只使用了一个字符串,需要复制。

至于另一个问题——你应该看一下你正在生成的代码(正如我在别处建议的那样,你可以弹出一点 PROBE 来检查 COLLECT 函数):

[
    t: text "message number: 1" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 2" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 3" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 4" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 5" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 6" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 7" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 8" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 9" field "entry" button "Click" [t/text: "clicked"] return 
    t: text "message number: 10" field "entry" button "Click" [t/text: "clicked"] return
]

如您所见,您不断地重新分配 t,所以最后它只引用最后一张脸。

这里有几个选项——最突出的是生成您要分配 text 面孔的名称。在你的 FOREACH 循环中:

keep compose/deep [
    (to set-word! rejoin ["t-" i])
    text (rejoin ["Message Number: " i])
    field "entry"
    button "Click" [
        set in (to word! rejoin ["t-" i]) 'text "clicked"
    ]
    return
]

请注意,为了简化块创建,我使用了这一行:

set in (to word! rejoin ["t-" i]) 'text "clicked"

这构成(在第一个实例中):

set in t-1 'text "clicked"

IN returns 绑定到给定上下文(面部对象 t-1)的给定单词 ('text) 然后 SET"clicked".

更新

此方法甚至不使用单词名称,仅使用公共父级将按钮连接到标签:

view collect [
    keep [below space 0x0]
    foreach i myRange 10 [
        keep compose/deep [
            panel [
                origin 0x0
                text (rejoin ["Message Number: " i])
                field "entry"
                button "Click" [face/parent/pane/1/text: "clicked"]
            ]
        ]
    ]
]