golang:隐式vs显式func定义

Consider this package:

package A
var X="change me"
var Y=func(i int) int { return i*i) }
func Z(i int) int { return -i) }

The two explicit variables (X,Y) can be changed in another package, say main...

package main
import "A"
func main () {
    A.X="done"
    A.Y=func (i int) int { return i*i*i }
    print(A.X,A.Y(7))
    //... but A.Z apparently can't be changed.
    //A.Z=func (int i) int { return i*i*i } //main.go:8: cannot assign to A.Z
}

Obviously there's a difference between defining a func variable (like Y) and an explicit func (like Z). I have googled this but not found much in the way of enlightenment. It almost seems as if var SomeFunc=func (...) defines indeed a variable, but func SomeFunc(...) defines a constant.

PS: A small goodie I found while researching this which I have not seen mentioned in the Go books I've read so far. A dot before a package import imports names without them having to be qualified:

package main
import . "A"
func main () {
    X="done"
    Y=func (i int) int { return i*i*i }
    print(X,Y(7))
}

There's a difference between declaring a variable initialized with a function value:

var Y=func(i int) int { return i*i) }

and declaring a function:

 func Z(i int) int { return -i) }

The specification says this about declarations:

A declaration binds a non-blank identifier to a constant, type, variable, function, label, or package.

The specification also says:

A function declaration binds an identifier, the function name, to a function.

The declaration of Y binds a variable to the name. This variable is initialized with a function value. The declaration of Z binds a function to the name.

If an explicit period (.) appears instead of a name, all the package's exported identifiers declared in that package's package block will be declared in the importing source file's file block and must be accessed without a qualifier.

func SomeFunc(), in essence creates a strong/constant/immutable binding of the identifier SomeFunc to the function you define. When you create a variable like so:

var (
    SomeFunc = func(i int) int {
        return i * 2
    }
)

You create a global variable of the type func(int) int. You can reassign this variable later on. This is something you can't really do with a func SomeFunc identifier. Simply put, this is because func SomeFunc() binds the function Directly to the identifier. The var SomeFunc approach creates a variable (type func(int) int in this case), and that variable is initialised using the function you're assigning. As is the case with variables: reassignment is possible.

Example

What you can do with functions, is shadow them using a scoped variable. This will probably get flagged by most linters, but it's a technique/trick that sometimes can be useful in testing

Example

As for the dot-imports: Please don't do that unless there's a very, very, very good reason for it. A good reason would be you writing a package that adds to an existing one, so you no longer import an existing one, but import your own. Think of it as extending a package. 99% of the time. Don't, whatever you do, use it to quench errors when you import encoding/json to add json serialization annotations to a struct. In those cases, use an underscore:

package foo
import (
    "encoding/json"
)

type Bar struct {
    Foobar string `json:"foobar"`
}

func New() *Bar {
    &Bar{"Default foobar"}
}

Don't know about golang 1.8, but packages like that could result in compiler errors (package encoding/json imported but not used). To silence that error, you simply changed the import to:

import(
    _ "encoding/json"
)

The dot-packages, underscores, and package aliases all follow the same rule: use them as little as possible.


Code used in examples:

package main

import (
    "fmt"
)

var (
    SomeFunc = func(i int) int {
        return i * 2
    }
)

func main() {
    fmt.Println(SomeFunc(2)) // output 4
    reassign()
    fmt.Println(SomeFunc(2)) // output 8
    shadowReassign()
    fmt.Println(SomeFunc(2)) // output 2
}

// global function
func reassign() {
    // assign new function to the global var. Function types MUST match
    SomeFunc = func(i int) int {
        return i * 4
    }
}

// assign function to local reassign variable
func shadowReassign() {
    reassign := func() {
        // same as global reassign
        SomeFunc = func(i int) int {
            return i
        }
    }
    reassign()
}