用*实例化var时,单例测试不起作用

I'm following the Singleton design pattern as described in this book (https://github.com/PacktPublishing/Go-Design-Patterns/blob/master/Chapter02/main.go) and I have this code in file "singleton2.go":

package singleton2

type Singleton interface {
  AddOne() int
}

type singleton struct {
  count int
}

//var instance = &singleton{}
var instance *singleton

func GetInstance() *singleton {
  if instance == nil {
    return new(singleton)
  }
  return instance
}

func (s *singleton) AddOne() int {
  s.count++
  return s.count
}

Then I have this test file (singleton2_test.go):

package singleton2

import "testing"

func TestGetInstance(t *testing.T) {
  counter1 := GetInstance()
  if counter1 == nil {
    t.Fatal("expected pointer to Singleton after calling GetInstance(), not nil")
  }

  expectedCounter := counter1

  currentCount := counter1.AddOne()
  if currentCount != 1 {
    t.Errorf("After calling for the first time to count, the counter must be 1 but it is %d", currentCount)
  }

  counter2 := GetInstance()
  if counter2 != expectedCounter {
    t.Errorf("Expected same instance in counter2 but it got a different instance.")
    t.Logf("Got %v, want %v", counter2, expectedCounter)
  }

  currentCount = counter2.AddOne()
  if currentCount != 2 {
    t.Errorf("After calling AddOne() using second counter, the count must be 2, but it was %d", currentCount)
  }

}

The problem is that tests always fail:

--- FAIL: TestGetInstance (0.00s)
    singleton2_test.go:20: Expected same instance in counter2 but it got a different instance.
    singleton2_test.go:21: Got &{0}, want &{1}
    singleton2_test.go:26: After calling AddOne() using second counter, the count must be 2, but it was 1
FAIL
exit status 1
FAIL    github.com/d3c3/design_patterns/singleton/singleton2    0.029s

Interestingly, if I change this line var instance *singleton to this line var instance = &singleton{} tests pass !? Why is that? IMO, it should work also with "var instance *singleton"

Can anyone explain this difference in behavior?

Follow the logic of your code and it's apparent where the problem is.

When you declare, but do not initialize the singleton (var instance *singleton) then instance is nil. Calling GetInstance evaluates instance == nil as true and returns a new *singleton every time it is called. That is why counter2 will never equal expectedCounter - each call to GetInstance is returning a new counter instance.

When you initialize the singleton instance (var instance = &singleton{}) then calls to GetInstance will return that singleton instance since it is not nil.

I imagine you'd want to modify GetInstance to something like this:

func GetInstance() *singleton {
    if instance == nil {
        instance = new(singleton)
    }
    return instance
}

EDIT

Although you didn't mention that you need this singleton to be thread-safe, user colminator correctly points out that instantiating a singleton this way can cause multiple go-routines to instantiate their own instance of the singleton, defeating the purpose of having one. Given how prolific concurrency is in Golang it's probably helpful to learn more! Check out the link he posted here.