I'm having a hard time with updating a sequence of objects in a for loop. It seems (at least for the objects) the type has to be declared as a "ref object" in order to be able to mutate in a loop. Otherwise loop throws an Error: 'i.x' cannot be assigned to.
How about sequence of tuples? It does not seem I can use 'ref' in this case.
type AAA = tuple[x:int]
type BBB = object
x:int
type CCC = ref object
x:int
var a : AAA = (x:1)
var b : BBB = BBB(x:2)
var c : CCC = CCC(x:2)
var aaa : seq[AAA] = @[a,a,a]
var bbb : seq[BBB] = @[b,b,b]
var ccc : seq[CCC] = @[c,c,c]
# for i in aaa:
# i.x=3 # does not work
# for i in bbb: # does not work - 'i.x' cannot be assigned to
# i.x=3
for i in ccc:
i.x=3 # works
echo i[]
This works:
for i in 0..aaa.high:
aaa[i].x=3
echo aaa
# @[(x: 3), (x: 3), (x: 3)]
It seems that the for ... in ... syntax works a bit like using let. This does not compile:
for i in 0..aaa.high:
let elem = aaa[i]
elem.x=3 # does not compile
Whereas this (with var) compiles, but does not work:
for i in 0..aaa.high:
var elem = aaa[i]
elem.x=3 # does not compile
echo aaa
# @[(x: 1), (x: 1), (x: 1)]
To get a kind of "mutable reference" to a sequence item, you'd have to use a pointer (at least I know no more elegant way):
for i in 0..aaa.high:
var elem = addr(aaa[i])
elem.x=3 # shortcut for elem[].x=3
echo aaa
# @[(x: 3), (x: 3), (x: 3)]
Quote: "Use the system.mitems iterator instead of the implicit items iterator." (Araq)
How to bring the systems.mitems iterator into the scope of the for loop?
By the way, I did'nt know that I can assign something to an extracted value. I thougt that the
for i in 0..aaa.high:
i is an immutable (value).
jdm: Whereas this (with var) compiles, but does not work:
Tuples have copy semantics and you're modifying the copy. Try one of the following:
for i in 0..aaa.high:
template t: expr = aaa[i]
t.x = 3
echo aaa
Or, as suggested by Araq:
for item in aaa.mitems:
item.x = 3
echo aaa