Difference between Symbols and Vars in Clojure

前端 未结 3 482
野的像风
野的像风 2020-11-30 22:37

I\'m always a bit confused about Symbols and Vars in Clojure. For example, is it safe to say that + is a symbol which is used to denote a var, and this var points to a value

3条回答
  •  悲哀的现实
    2020-11-30 23:06

    There's a symbol + that you can talk about by quoting it:

    user=> '+
    +
    user=> (class '+)
    clojure.lang.Symbol
    user=> (resolve '+)
    #'clojure.core/+
    

    So it resolves to #'+, which is a Var:

    user=> (class #'+)
    clojure.lang.Var
    

    The Var references the function object:

    user=> (deref #'+)
    #
    user=> @#'+
    #
    

    (The @ sign is just shorthand for deref.) Of course the usual way to get to the function is to not quote the symbol:

    user=> +
    #
    

    Note that lexical bindings are a different mechanism, and they can shadow Vars, but you can bypass them by referring to the Var explicitly:

    user=> (let [+ -] [(+ 1 2) (@#'+ 1 2)])
    [-1 3]
    

    In that last example the deref can even be left out:

    user=> (let [+ -] [(+ 1 2) (#'+ 1 2)])
    [-1 3]
    

    This is because Var implements IFn (the interface for Clojure functions) by calling deref on itself, casting the result to IFn and delegating the function call to that.

    The visibility mechanism used when you define private functions with defn- is based on metadata on the symbol. You can bypass it by referring directly to the Var, as above:

    user=> (ns foo)
    nil
    foo=> (defn- private-function [] :secret)
    #'foo/private-function
    foo=> (in-ns 'user)
    #
    user=> (foo/private-function)
    java.lang.IllegalStateException: var: #'foo/private-function is not public (NO_SOURCE_FILE:36)
    user=> (#'foo/private-function)
    :secret
    

提交回复
热议问题