The new function

We declare a variable of type p, and change the value of the variable to “micro guest bird nest” :

Func main() {var p *string *p = "FMT.Println(*p)"}

Error:

panic: runtime error: invalid memory address or nil pointer dereference

This is because the default value for a variable of pointer type is nil if no memory is allocated. It has no memory to point to, so it can’t be used. If you want to use it, you can allocate a block of memory to it. You can use the new function:

Func main() {var p *string p = new(string) *p = "FMT.Println(*p)"}

The above example works fine, but what does the built-in function new do? Source code analysis:

// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly
// allocated zero value of that type.
func new(Type) *Type

Function:

  • Request a block of memory based on the type passed in, and return a pointer to that memory
  • The data to which a pointer points is the zero value of that type
  • For example, if the type passed in is string, the string pointer is returned, and the string pointer points to an empty string

Variable initialization

When a variable is declared and assigned, it is called initialization.

Initialize a string variable:

Var s = s1; var s = s1;

Pointer variable initialization

We can define a function to initialize a pointer variable

Package main import "FMT" func main() {pp:=NewPerson(" FMT ",18) FMT.Println(pp) //&{FMT "FMT ",18}} type person struct { name string age int } func NewPerson(name string,age int) *person{ p := new(person) p.name = name p.age = age return p }

Make function

We’ve already seen that when we use make to create a map, we actually call makemap:

// makemap implements Go map creation for make(map[k]v, hint). func makemap(t *maptype, hint int, H *hmap) *hmap{// omit irrelevant code}

The makemap function returns the *hmap type, which is a structure defined as follows:

// A header for a Go map.
type hmap struct {
   // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
   // Make sure this stays in sync with the compiler's definition.
   count     int // # live cells == size of map.  Must be first (used by len() builtin)
   flags     uint8
   B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
   noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
   hash0     uint32 // hash seed
   buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
   oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
   nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
   extra *mapextra // optional fields
}

As you can see, the map keyword is very complex, including the map size count, buckets, etc. To use hmap, you can simply use a new function that returns an *hmap. You also need to initialize it, which is what make does:

m := make(map[string]int,10)

The make function looks a lot like the custom NewPerson function above. In fact, the make function is a factory function of the map type. It can create different types of maps depending on the type of key-value pairs passed to it, and it can also initialize the size of the map.

The make function is not only a map factory function, but also a chan and slice factory function. It can be used for all three types of initialization, slice, Chan, and Map.

  • The new function is used only to allocate and clear memory. It is not used very often.
  • The make function is only used to create and initialize the three built-in types, slice, chan, and map, because these three types have complex structures, such as the type of internal elements to be initialized in advance, the length and size of the slice, etc.