Generally speaking, both are used like memory aliases. But, a variable more directly aliases a memory offset at compile time, and a key informs a memory mapping algorithm at runtime.
Conceptually, the primary difference is one of scope: Whether the alias operates at compile time versus runtime.
Functionally, the primary difference is one of runtime mutability (of all such aliases): Whether the collection of aliases can be changed at runtime. You can't compile your code and add Int32 xyz
at runtime. But, you can add key xyz
to a collection.
Practically, the primary difference is lookup strategy and efficiency: Variables hold memory offsets. Using them is fast. Keys are piped through a lookup algorithm that, comparatively speaking, eventually determines a memory offset and returns its contents.
Lots of work is done at runtime to make keys work. Variables are sort of just there.