Is it possible to write a loop such that the loop variable can be assigned to? The following example:
import strutils
let s = "a \n b\n c \n"
for line in s.splitLines:
line = line.strip
# TODO further procession of line
fails to compile, with a Error: 'line' cannot be assigned to. Can this be avoided, or does another variable have to be introduced to get around it?
You can no way modify the string via this iterator. The easiest way: split it into a sequence via the same-named proc (just save it into a variable), and then in the for loop use mitems iterator on it, it allows modifying. Then join the sequence into a new string.
Or w/o modifying: use a variable in the loop (var s=line.strip), do any processing, then concatenate into a new string, defined empty before the loop.
To syntax-highlight Nim code in the forum posts wrap it like in the hint below the textarea.
You can use the mitems proc. you should read lib/system.nim and familiarise yourself with the available procs.
var lines = s.splitLines
for line in lines.mitems:
line = line.strip
In this case it's best to introduce a new let binding. This way you shadow the for loop variable so there is no way to accidentically refer to it:
import strutils
let s = "a \n b\n c \n"
for line in s.splitLines:
let line = line.strip
# TODO further procession of line
In this case it's best to introduce a new let binding.
Ah, that's the pointer I needed. Thanks.
import strutils
let s = "a \n b\n c \n"
for unstripped_line in s.splitLines:
let line = unstripped_line.strip
Gives "redifinition of 'line'" error...
Ooops. IMO it should be allowed though. Should for loops open 2 new scopes rather than 1? One for the iteration vars, one for the loop body?
it's what I was trying to avoid
I dunno why ... the code is clearer, and sometimes you end up wanting the unstripped line, e.g., to print it.
For example, I often use i and s as scratch variables for integers and strings, repeatedly, in functions where the meaning of how they're used is localised and easy to grasp.
There's a big difference between reusing names in different scopes and reusing them in the same scope. The latter begs for bugs.
In this case, line has the meaning for me of "the current line of text I'm working on, in whatever state of processing I want it to be in at this point in the loop".
If line is undergoing multiple transformations, then a) that sounds like an inefficient design, b) again, the code would be clearer if the name was different, reflecting the semantics of the transformation, and c) you need var, not let.
I assume this was implemented since this now runs without the error mentioned above:
import strutils
let s = "a \n b\n c \n"
for line in s.splitLines:
let line = line.strip
echo '>', line, '<'
Output:
>a<
>b<
>c<
><