The concept of syntactic sugar was introduced by British computer scientist Peter Landin, referring to certain types of syntax in programming languages that do not affect functionality but are convenient to use. Syntactic sugar, also known as sugared syntax, does not alter the functionality, and the compiled result is the same as without using syntactic sugar.

1. Short Variable Declaration :=

  1. Multiple variable assignments may redeclare variables (This does not introduce new variables but only changes the values of existing variables.)
  2. Scope issues

2. Variadic Parameters (...parameters)

During development, you might encounter scenarios where a method originally takes a slice as a parameter and iterates over it internally. Now, you need to add another method that takes a single element as a parameter. The processing logic is exactly the same except for the iteration. To avoid adding a highly similar method, you might think of certain built-in functions in Go that handle similar scenarios with an unfixed number of parameters, such as append, which can append either a slice or a single element. Looking at the source code:

1func append(slice []Type, elems ...Type) []Type

append uses variadic parameters.

1result := []int{1, 3}
2data := []int{5, 7}
3result = append(result, data...) // Equivalent to result = append(result, data, data)
4// Final result == []int{1, 3, 5, 7}
  1. Variadic parameters are declared in the function parameter list using name ...Type and must be the last parameter (only one variadic parameter is allowed).
  2. Variadic parameters are treated as slices inside the function.
  3. Variadic parameters can be omitted, and the function will treat them as a nil slice.
  4. Variadic parameters can accept slices (the slice used inside the function shares the same storage space as the passed slice. In other words, if the slice is modified inside the function, it may affect the external caller).
  5. Variadic parameters must be of the same type (if different types are needed, they can be defined as interface{}).

3. The init() Function

  1. Multiple init() functions per package:

    • In a package, you can define multiple init() functions distributed across different files.
    • Each init() function will be called automatically, and the calling order is based on the alphabetical order of the filenames.
  2. Multiple init() functions per file:

    • In a single file, you can define multiple init() functions.
    • These init() functions will be executed in the order they appear in the file.
  3. init() functions are executed only once:

    • No matter how many times the package is imported, the init() functions will only be executed once.
    • Even if the package is imported by multiple files, the init() functions will only be executed once.
  4. Execution timing of init() functions:

    • init() functions are called automatically after the package’s variables are initialized and before the main() function is executed.
    • If a package is imported by multiple packages, its init() functions will be called before the init() functions of the importing packages.
  5. Reading init() functions from other packages:

    • When the main() function needs to read only the init() function from a package without importing additional functions, you need to use _ for importing.
      1import (
      2    _ "xxxx"
      3)
      
    • If this is not done, the compiler will throw an error because main() does not use anything other than init().
    • If multiple init() functions from different packages need to be imported, they will be read in the order of the import statements.