Search code examples
vimdestructuring

In Vimscript, how to skip over elements in a destructuring assignment from a list?


Vimscript has something like destructuring assignment for lists. For example:

:let [a,b,c] = [1,2,3]

What if I don't care about the first element but I still want to bind b and c? Is there some "wildcard" that I can use to avoid giving a name to the 1?


Solution

  • Just assign those fields to a variable name that makes it clear you're ignoring those values. The _ variable is a great convention for that.

    let [_, b, c] = [1, 2, 3]
    

    Or, to ignore the first two terms:

    let [_, _, c] = [1, 2, 3]
    

    Note you can use it more than once in a :let-unpack assignment.

    In some languages, such as Python, the _ variable special, in that assignments to it are not stored anywhere. That's not the case in Vimscript, a variable with that name is valid and does exist. But if you're performing this assignment from inside a function (which is likely to be the case), then the variable scope will be limited to that function and the namespace pollution shouldn't be concerning.


    Here's a real life example usage from the well known vim-figitive plug-in by tpope:

    let [_, to, changes; __] = matchlist(a:line, '^ \(.\{-\}\) \+|\zs \(.*\)$')
    

    Note it uses the ; syntax to ignore all fields from the fourth onwards (that's useful to know when unpacking large lists.) It uses _ to ignore the first field and __ to ignore the rest. (Note that using _ for both would have been fine as well.)

    The Vim documentation also makes references to using _ as a name for a variable to be ignored. For an example usage of map():

    If you do not use "key" you can use a short name:

    call map(myDict, {_, val -> 'item: ' . val})