1

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))
}
2
  • 1
    What's your question? Commented Mar 24, 2017 at 15:09
  • This is pretty much a duplicate of stackoverflow.com/q/23925005/5419599, but that question has more answers. Commented May 29, 2019 at 5:47

1 Answer 1

3

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()
}
Sign up to request clarification or add additional context in comments.

4 Comments

Just a thought. It may be useful to add another call in main to reassign, then print to show that the original global still works and wasn't overwritten. Just for complete clarity.
@elias: so in effect what you're saying is that func SomeFunc(...) is indeed defining a constant, something like "const SomeFunc = func (...)". (This is not valid Go, I know.) I have not really seen an explanation of why that should be the case in the Go docs. As to dot imports, I agree, this should be used sparingly though there are valid usage cases. I mentioned it because I had not seen it before (and I've read a lot about Go in the last couple weeks).
@RayfenWindspear: I am not sure I understand your comment.
@CharlesPerrin: One of the most important reasons for binding identifiers to a static function directly is quite simply: packages. If you export a function from a package, it's effectively read-only. Do the same thing with a variable and you'll end up with a package that can be altered by anyone (reassigning an exported variable). As for the previous comment: RayfenWindspear is, I believe, referring to shadowing the global variable

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.