:set
is used for internal options and handles the types of the option. It allows things like inversion of boolean options (e.g. :set invpaste
) adding and removing settings from a list (e.g. :set dictionary-=/tmp/myfile
).
:let
, on the other hand, allows access to a plethora of changeable things in vim, including regular variables, options, registers, etc. and the value being set is the result of evaluating an expression, instead of a simple value like with :set
, which means :let
gives you access to math, string manipulation, and functions.
For example, you can :let &dictionary=/tmp/myfile
to set the option 'dictionary'
to /tmp/myfile
(thus modifying the same option shown above in the :set
example)
You can set a global variable with :let g:myvar=42
. The prefix you asked about provides scope. Doorknob's answer covers the scoping very well.
You can :let @a="Some text"
to change the contents of register a to contain Some text
, which you could later paste with "ap
for example.
You can :let $PATH = $PATH . ":/home/me/bin"
to append your own bin directory to the PATH
environment variable, which is passed to any external commands executed by Vim (this works for any environment variable).
Although let
has some pretty powerful abilities (like :let $MYFILE = @%
to set an environment variable to the filename of the current buffer), it doesn't know that a setting is a boolean, so it doesn't offer nice accesses or error checking like :set
does.
In the end, it's about using the best tool for the job. If you want to simply modify an option, :set
is your tool. If you want to move information around between registers, options, variables, or base your value on the result of an expression, then :let
is your tool.
Although you explicitly asked about Vim, another thing to note is that :set
is more common in the vi/Vim families, where :let
is less common (for example, nvi doesn't have a let
command, and viemu doesn't provide access to registers via let
).