Go learning (basic)


  1. The init function executes before the main function

    func init() {
        fmt.Println("This is init function")
    func main() {
        fmt.Println("This is main function")
    // Output content
    // This is init function
    // This is main function
  2. The identifier (including constant, variable, type, function name, structure field, etc.) starts with an uppercase letter, so the object using this identifier can be used by the code of the external package (the client needs to import), which is called export
    (similar to public in object-oriented);

  3. If the identifier starts with a lowercase letter, it is not visible outside the package, but it is invisible and available inside the whole package
    (similar to private in object-oriented)

  4. A line represents the end of a statement (it does not need to be ended with a semicolon; it is automatically completed by the compiler)
    If you intend to write multiple statements on the same line, you must use; Distinguish (not recommended)

  5. Number type

    type describe
    int8/int16/int32/int64 Signed integer
    uint8/uint16/uint32/uint64 Unsigned integer
    float32/float64 IEEE-754 32/64 bit floating point number
    complex64/complex128 32 / 64 bit real and imaginary numbers
    byte Similar to uint8
    rune Similar to int32
    uint 32 or 64 bit
    int Same size as uint
    unitptr Unsigned integer used to hold a pointer
  6. variable

    Global variables and local variables can have the same name, refer to global variable

    // Variable declaration
    var identifier type
    // 1. Specify the variable type (default value is used if no assignment is made)
    var v_name v_type
    var v_name v_type = value
    // 2. Type derivation
    var v_name = value
    // 3. Omit var and declare with: =; Can only be used to declare local variables
    v_name := value
    // The definition of: = is correct
    var outer = true
    func main() {
        // a. Variable definitions defined outside the print method
        // b. If it is a global variable, it can be redefined (including different types) (fixme should not be the same variable)
        outer := "use := Redefine variables"
        // c. The following definitions cannot be compiled
        // var inner [string] = "local variable"
    	// fmt.Println(inner)
    	// inner: = "redefining local variables cannot be compiled"
    	// fmt.Println(inner)
    // Local variable: multiple variables of the same type
    // 1. Specify the type (three variables have the same type; they can be global variables)
    var vname1,vname2,vname3 type
    vname1,vname2,vname3 = v1, v2, v3
    // 2. Type derivation (can be different types; can be global variables; parallel | simultaneous assignment)
    var vname1,vname2,vname3 = v1, v2, v3
    // 3. Initialization declaration (can be of different types; variables must not be declared inside the method; parallel | simultaneous assignment)
    vname1,vname2,vname3 := v1, v2, v3
    // Global variable: multiple variable declarations with different types (only global variables)
    var (
    	v_name_1 type1
        v_name_2 type2
  7. Value type and reference type

    1. Value type
      1. All basic types such as int, float, bool and string belong to value types. Variables using these types directly point to values in memory
      2. When the equal sign = is used to assign the value of one variable to another variable, such as j = i, the value of i is actually copied in memory
      3. You can use & i to get the memory address (addresser) of variable i
      4. The value of a variable of value type is stored on the stack
    2. reference type
      1. More complex data usually needs to use multiple values, and these data are generally saved with reference types
      2. A reference type variable r1 stores the memory address (number) where the value of r1 is located, or the location of the first value in the memory address (this memory address is also called a pointer)
      3. Multiple values pointed to by a pointer of the same reference type can be continuous or scattered in memory
  8. Local variables are forbidden to be declared and not used; Global variables allow only declarations that are not used

    var outer string = "Global variables allow only declarations that are not used"
    func main() {
        // Unused variable 'inner'
        var inner = "Local variables are prohibited from being declared and not used"
  9. If you want to simply exchange the values of two variables, you can use a, b=b, a

  10. Blank identifier_ It is also used to discard values, such as value 5 in, B: = abandoned in 5 and 7
    _ In fact, it is only a writable variable and its value cannot be obtained
    (in Go language, you must use all declared variables, but sometimes you don't need to use all the return values from a function)

  11. Parallel assignment is also used when a function returns multiple return values

    val, err = Func1(var1)


  1. The data types in constants can only be Boolean, numeric (integer, floating point and complex) and string

  2. Define format

    // Type descriptors can be omitted
    const identifier [type] = value
    // Multiple variables of the same type can be defined at the same time
    const c_name_1, c_name_2 = value1, value2
    // You can define local and global constants with the same name
    const a1, a2, a3 = "a1", 23, true
    func method() {
        // This definition will not report an error
        const a1, a2 = "aa1", "aa2"
        // Give priority to the output of local variable definitions. If not, the output of global variable values
        fmt.Println(a1, a2, a3)
  3. Constants can also be used as enumerations

    const (
    	Unknown = 0
    	Female  = 1
    	Male    = 2
  4. In the constant definition, len(), cap(), unsafe.Sizeof() can be used to calculate the value of the expression (it must be a built-in function)

    const (
    	a = "abc"
    	b = len(a)
    	c = unsafe.Sizeof(a)
  5. iota, a special constant, can be considered as a constant that can be modified by the compiler
    When each const keyword appears, it is reset to 0, and then before the next const appears, the number represented by iota will automatically increase by 1

    // Definition one
    const (
    	a = iota
    	b = iota
    	c = iota
    // Continue with definition 2
    // const appears and the value is reset
    const (
    	d = iota
    	e = iota
    	f = iota
    // a=0,b=1,c=2
    // d=0,e=1,f=2
    // Abbreviated as
    const (
    	a = iota
  6. More complicated usage

    // Example 1
    const (
    	a = iota // a=0
    	b        // b=1
    	c        // c=2
    	d = "ha" // d="ha",iota+=1=3
    	e        // e="ha",iota+=1=4
    	f = 100  // f=100,,iota+=1=5
    	g        // g=100,,iota+=1=6
    	h = iota // Recovery count h=7
    	i        // i=8
    // Example 2 
    const (
    	i = 1 << iota // i=1<<0=1
    	j = 3 << iota // j=3<<1=6
    	k             // k=3<<2=12
    	l             // l=3<<3=24


  • Arithmetic operator

    Including +, -, *, /,%, + +--

    func method() {
        a := 10
    	b := 20
    	var c int
        c = a + b
    	c = a - b
    	c = a * b
    	c = a / b
    	c = a % b
        // Equivalent to: a=a+1
        // Equivalent to: a=a-1
        // There is no operation of + + a or -- a
  • Relational operator

    Including = =,! =, >, <, > =<=

  • Logical operator

    Including & &, |!

    1. No single and, single or
    2. The style of go is that you don't have to use parentheses to wrap logical operator calculations
    func method() {
        a := true
        b := true
        // The style of go is that you don't have to wrap logical operations in parentheses
        if a || b {
    		fmt.Println("a||b is true")
        // There is no single and, single or in the logical operator
        // if a | b{}
  • Bitwise Operators

    You can operate on the binary bits of integers in memory

    Including &, |^

    operator explain
    & And operation, all true is true
    | Or operation, all false is false
    ^ XOR operation. The same is false and the different is true
    << Shift left operator, shift n bits to the left is multiplied by 2 to the nth power (the high bit is discarded and the low bit is supplemented by 0)
    >> Shift right operator, shift n bits right is divided by 2 to the nth power
  • Assignment Operators

    operator explain example
    = Assign the value of an expression to an lvalue C = A + B
    += Add and assign C += A equals C = C + A
    -= Subtraction before assignment C -= A equals C = C - A
    *= Multiply and assign C *= A equals C = C * A
    /= Divide and assign C /= A equals C = C / A
    %= Assign value after remainder C% = a equals C = C% a
    <<= Left shift assignment C < < 2 equals C = C < < 2
    >>= Assignment after shift right C > > = 2 equals C = C > > 2
    &= Bitwise and post assignment C & = 2 equals C = C & 2
    ^= Assignment after bitwise XOR C ^= 2 equals C = C ^ 2
    |= Bitwise or post assignment C | 2 equals C = C | 2
  • Other Operators

    operator explain example
    & Variable memory address &var_ Name returns the actual address of the variable
    *(fixme) Pointer variable *var_name is a pointer variable
  • Operator priority (from high to low)

    priority operator
    7 ^ !
    6 * / % <> & &^
    5 + - | ^
    4 == != < = >
    3 <-
    2 &&
    1 ||

Conditional statement

sentence describe
if statement An if statement consists of a Boolean expression followed by one or more statements.
if...else statement An optional else statement can be used after the if statement. The expression in the else statement is executed when the Boolean expression is false.
if nested statement You can embed one or more if or else if statements in an if or else if statement.
switch statement switch statements are used to perform different actions based on different conditions.
select statement The select statement is similar to the switch statement, but select randomly executes a runnable case. If there is no case to run, it will block until there is a case to run.


  • The switch statement executes from top to bottom until a match is found, and there is no need to add a break after the match

  • You can test multiple possible qualified values in one case at the same time, separated by commas

  • All case candidate values must be of the same type as the switch variable (expression) (otherwise, compilation error)

  • There are two ways to write

    //Variable var_name can be any type, while val1 and val2 can be any value of the same type
    switch var_name {
        case val1:
        	// There is no need to add break in the match
        case val2:
        	// Multiple value s can exist in a case


    func method() {
        grade := "B"
    	marks := 90
    	// Writing method I
    	switch marks {
    	case 90:
    		grade = "A"
        // case can have multiple values that may meet the conditions at the same time
    	case 80:
    		grade = "B"
            // break is not required in case
    		grade = "C"
    	// Writing method 2
    	switch {
    	case grade == "A":
        // case can have multiple values that may meet the conditions at the same time
    	case grade == "B", grade == "C":
            // break is not required in case
    	fmt.Println("The grade is: ", grade)

Type Switch(fixme)

The switch statement can also be used for type switch to determine the type of variable actually stored in an interface variable

switch x.(type){
    case type:
    case type:
    /* You can define any number of case s */
    default: /* Optional */


func method() {
    // Define interface
    var x interface{}
	switch i := x.(type) {
	case nil:
		fmt.Printf(" x Type of :%T", i)
	case int:
		fmt.Printf("x yes int type")
	case float64:
		fmt.Printf("x yes float64 type")
    // The case item can also be a func
	case func(int) float64:
		fmt.Printf("x yes func(int) type")
    // You can test multiple values that may meet the criteria
	case bool, string:
		fmt.Printf("x yes bool or string type")
		fmt.Printf("Unknown type")


  1. It is similar to select in the operating system
  2. It has a similar control structure to switch, but the expressions in these case s must be Channel transceiver operations
  1. Is a control structure;
  2. select randomly executes a runnable case;
  3. If there is no case to run, select will block until there is a case to run;
  4. The default (if any) must be executed normally
select {
    case communication clause  :
    case communication clause  :
    /* You can define any number of case s */
    default : /* Optional */
  1. Each case must be a Channel
  2. All Channel expressions are evaluated
  3. All expressions sent are evaluated
  4. If any Channel can execute, it will execute; Others ignored
  5. If there are multiple case s that can be run, select will randomly and fairly select one to execute; Others ignored
  6. If there is no case to run:
    1. Default exists, execute default
    2. No default, blocking until a channel is available (Go will not evaluate the channel or value)

The knowledge points of select are summarized as follows:

  1. The select statement can only be used for channel read and write operations
  2. The case condition (non blocking) in select is executed concurrently. Select will select the case condition whose operation is successful first to execute. If multiple conditions return at the same time, one execution will be selected randomly. At this time, the execution order cannot be guaranteed. For a blocked case statement, it will be executed until there are channels available for operation. If there are multiple channels available for operation, one of the cases will be randomly selected for execution
  3. For the case conditional statement, if there is a read / write operation with the channel value of nil, the branch will be ignored, which can be understood as deleting the case statement from the select statement
  4. If there is a timeout condition statement, the judgment logic is that if there is no case that meets the condition within this time period, the timeout case will be executed. If an operable case occurs during this period, the case will be executed directly. Timeout statements are generally used instead of default statements
  5. An empty select {} will cause a deadlock
  6. For select {} in for, it may also cause excessive cpu consumption

Circular statement

Cycle type describe
for loop Repeat statement block
loop nesting Nest one or more for loops within a for loop

Cycle type

for loop

// Of the three forms, only one uses a semicolon
// 1. Same as for of C (same as Java, without parentheses)
for init; condition; post { }
// 2. Same as C's while
for condition { }
// 3. Same as for(;) of C
for { }

The range format of the for loop can iterate over slice, map, array, string, etc

for key, value := range oldMap {
    newMap[key] = value


func method() {
    numbers := [6]int{1, 2, 3, 5}
    for i, x := range numbers {
		fmt.Printf("The first %d position x Value of = %d\n", i, x)

Nested loop

// Same as Java, no parentheses
for [condition |  ( init; condition; increment ) | Range]
   for [condition |  ( init; condition; increment ) | Range]

Loop control statement

Control statement describe
break statement It is often used to break the current for loop or jump out of the switch statement
continue statement Skip the remaining statements of the current loop and proceed to the next loop.
goto Statement Transfers control to the marked statement.

goto (not recommended)

You can unconditionally transfer to the line specified in the process

It is usually used in conjunction with conditional statements to realize conditional transfer, form a loop, jump out of the loop and other functions

goto is generally not recommended to avoid confusing the program flow, making the program difficult to understand or debug

goto label
label: statement


// 1. Terminate nested loop
func method1() {
     for x := 0; x < 10; x++ {
        for y := 0; y < 10; y++ {
            if y == 2 {
                // Jump to the label (it will also terminate all loops, which is a bit similar to the use of label in Java)
                goto breakHere
                // Direct use will only exit the current cycle
                // break
    // Manual return to avoid entering the label
    // label

// 2. Code reuse
func method2() {
    err := firstCheckError()
    if err != nil {
        goto onExit
    err = secondCheckError()
    if err != nil {
        goto onExit


  1. The most basic code block used to perform a task
  2. There is at least one main function
  3. Logically, each function performs the specified task
  4. Function name, parameter list and return value (type, number and order) together constitute the function signature
  5. The standard library provides a variety of available built-in functions (existing in the builtin and unsafe standard libraries)
  6. Return value: fixme


// 1. Multiple values can be returned
// 2. If there is no return value, return_types can be defaulted  
// 3. The input parameter types are the same, and simple definitions can be used
func function_name( [parameter list] ) [return_types] {
   // function body
func function_name( [parameter list] ) (type1,type2,...,typeN) {
   // function body

func max(a, b int) int {
    // Method body omission
    return ret
func swap(x, y string) (string, string) {
	return y, x

Function parameters

Delivery type describe
pass by value Value passing refers to copying and passing a copy of the actual parameters to the function when calling the function, so that if the parameters are modified in the function, the actual parameters will not be affected.
Reference passing Reference passing refers to passing the address of the actual parameter to the function when calling the function. The modification of the parameter in the function will affect the actual parameter.

By default, the Go language uses value passing, that is, the actual parameters will not be affected during the call

An example of reference passing (specific usage to be studied):

// The reference passed into the body of the reference method is different
func swap(x *int, y *int) {
	var tmp int
	tmp = *x
	*x = *y
	*y = tmp

Function usage

Function usage describe
Function as value Functions can be used as values after they are defined
closure Closures are anonymous functions that can be used in dynamic programming
method A method is a function that contains the recipient
/* Declare function variables */
getSquareRoot := func(x float64) float64 {
    return math.Sqrt(x)
/* closure */
func getSequence() func() int {
	i := 0
	return func() int {
		i += 1
		return i
/* Function method */
func (variable_name variable_data_type) function_name([var_name type]) [return_type]{
   /* Function body*/

Function method: equivalent to a custom method owned by a class in Java

/* Define function fixme */
type Circle struct {
  radius float64

// The method belongs to a method in an object of type Circle
func (c Circle) getArea() float64 {
  //c.radius is an attribute in an object of type Circle
  return 3.14 * c.radius * c.radius
// The method definition is correct, but it is not a method of an object of type Circle
func getArea2(c Circle) float64 {
	return math.Pi * c.radius * c.radius
// Method can receive input parameters
func (c Circle) getPerimeter(x, y int) float64 {
	fmt.Println("x=", x, ",y=", y)
	return math.Pi * c.radius * 2

func main() {
  var c1 Circle
  c1.radius = 10.00
  // Method call
  fmt.Println("Area of Circle(c1) = ", c1.getArea())
  // getArea2 is not a method of a Circle class object
  // fmt.Println("Area of Circle(c1) = ", c1.getArea2())
  area := getArea2(c1)
  fmt.Println("area = ", area)
  fmt.Println("Perimeter of Circle(c1) = ", c1.getPerimeter(10, 15))

Variable scope

Variables can be declared in three places:

  • Variables defined in a function are called local variables
  • Variables defined outside the function are called global variables
  • Variables in a function definition are called formal parameters

local variable

  1. Declare in function body
  2. The scope is only in the function body
  3. Parameters and return value variables are also local variables

global variable

  1. Declaration outside the function
  2. It can be used in the whole package or even external packages (after being exported)

The names of global variables and local variables can be the same, but the local variables in the function will take precedence

Formal parameter (formal parameter)

Variables that appear in the function / method parameter table (used as local variables)

Initialize local and global variables

data type Initialize defaults
int 0
float32 0
pointer(fixme) nil


// statement
var variable_name [SIZE] variable_type
// initialization
// SIZE can not be written (brackets must be reserved), and will be automatically pushed to and set according to the number of values
var variable_name = [SIZE]variable_type{val_1,val_2,...,val_SIZE}
var variable_name = []variable_type{val_1,val_2,...,val_SIZE}
// Visit strategy

// Example
var balance [10] float32
balance := []int{1, 2, 5, 7, 8, 9, 3}
balance := [10]int{1, 2, 5, 7, 8, 9, 3}

Traverse reference [for loop] (#for loop)

A definition or reference that does not specify a length is actually Slice

Multidimensional array

// statement
var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type

// Example (2D array)
var a1 [3][4] int
var a2 = [3][4]int{
    {0, 1, 2, 3},   /*  The first row index is 0 */
    {4, 5, 6, 7},   /*  The index of the second row is 1 */
    {8, 9, 10, 11}, /*  The third row has an index of 2 */

Function transfer value

As a formal parameter, the length of the parameter array must be consistent with the passed in array (fixme array and slice distinguish???)

func method(arr [SIZE]type) [return_types] {}
func method(arr []type) [return_types] {}

Pointer (fixme)

Pointer variable: memory address pointing to the value

  1. The assignment must be the memory address of the corresponding variable, that is, PTR = & var_ name
  2. Add a * sign (prefix) before the pointer type to get the content pointed to by the pointer

Pointer declaration:

var var_name *var_type

// Example
var ip *int        /* Pointing integer */
var fp *float32    /* Point to floating point */


func method() {
    a := 201    /* Declare actual variables */
	var ip *int /* Declare pointer variables */
	ip = &a     /* Storage address of pointer variable */
    // ip = a / * error declaration*/
	fmt.Printf("variable a The memory address is: %x\n", &a)
	/* Use a pointer to access the value stored at the destination memory address */
	fmt.Printf("*ip Value of variable: %d\n", *ip)
	fmt.Printf("ip Value of variable: %d\n", ip)
// Output results
// The memory address of variable a is c00000aa058
// *Value of ip variable: 201
// Value of ip variable: 824634417240

Null pointer

  1. When a pointer is defined and not assigned to any variable, its value is nil, that is, a null pointer.

  2. Conceptually, nil, like null, None, nil and null in other languages, refers to zero value or null value.

  3. Pointer variables are usually abbreviated to ptr.

Null pointer judgment:

ptr == nil
ptr != nil

Pointer array

Declaration method:

var ptr [SIZE]*type

// Example: integer pointer array
var ptr [5]*int

Pointer to pointer

A pointer variable stores the address of another pointer variable

Declaration method:

var ptr **type

// Example
var ptr **int

Two * signs are required to access the pointer variable value pointing to the pointer

func method() {
    a := 3000
	var ptr *int
	var pptr **int
	/* Pointer ptr address */
	ptr = &a
	/* Pointer ptr address */
	pptr = &ptr
	/* Gets the value of pptr */
	fmt.Printf("variable a = %d\n", a)
	fmt.Printf("Pointer variable *ptr = %d\n", *ptr)
	fmt.Printf("Pointer variable to pointer **pptr = %d\n", **pptr)

Pointer as parameter

func method(x, y *var_type) {
    // The internal use of fixme needs to meet the * x *y format (all corresponding values are operated through the memory address)

structural morphology

A collection of data (similar to a class in Java) consisting of a series of data of the same or different types

Declaration method:

// Structure declaration
type struct_variable_type struct {
   member definition
   member definition
   member definition
// Structure variable declaration
var variable_name struct_variable_type
variable_name := structure_variable_type {value1, value2...valueN}

Use the dot (.) operator to access structure members. The format is: "structure. Member name"

// definition
type Books struct {
    title   string
    author  string
    subject string
    bookId  int

// variable
var book1 Books
book2 := Books{
    title:   "Go language",
    author:  "www.w3cschool.cn",
    subject: "Go Language course",
    bookId:  1,
// Property access

Structure pointer

// Pointer definition
var struct_pointer *struct_variable_type

// The use method is the same as above
var structPointer *Books
structPointer = &book2


  1. Slicing is an abstraction of arrays

  2. The length of the slice is not fixed. It supports additional elements and dynamic capacity expansion (the length of the array is not variable, and the slice is to solve this problem)

  3. Before the slice is initialized, it defaults to nil. At this time: len=cap=0

  4. append() and copy(): append and copy

// statement
// 1. General declaration
var identifier []type
// 2. Declare with make()
var identifier []type = make([]type, len)
// 3. make() declaration abbreviation
identifier := make([]type, len [,cap])
// fixme specifies the capacity (length is the length of the array and the initial length of the slice; capacity is optional)
make([]T, length [,capacity])

// Initialization (the following are sample abbreviations)
var slice_var = []type{val1,val2,...,valN}
slice_var := []type{val1,val2,...,valN}

slice_var_1 := slice_var[:] // slice_var is a slice reference
slice_var_2 := slice_var    // It seems OK to write so

slice_var_3 := slice_var[startIndexInclude:endIndexExclude] // Slice (array) interception
slice_var_4 := slice_var[startIndexInclude:] // Slice (array) interception
slice_var_5 := slice_var[:endIndexExclude] // Slice (array) interception

// Element append
numbers = append(numbers, 1,2,3,4)
// Copy

Language range

range keyword is used to iterate over elements such as array, slice, linked list channel or set map in the for loop

Personal understanding: use the for loop to traverse a keyword used in an array, slice, linked list or collection

Range expression First value Second value [optional]
Array or slice a [n]E Index i int a[i] E
String s string type Index i int rune int
map m map[K]V Key k K Value m[k] V
channel c chan E Element e E none
// When iterating over a string, index is the index and value is the character (Unicode value)
for index|key, value := array|slice|channel|map|string {
    // Business code


  1. Using hash implementation, it is an unordered set of key value pairs
  2. If the map is not initialized, the map is a nil map
  3. nil map cannot write key value pairs
    After making (), you can write again
  4. The make method cannot be used independently. You need to use fixme together: what does the make function mean??
  5. Determine whether the element exists in the map
/* Declare variables. The default map is nil */
var map_variable map[key_data_type]value_data_type
/* Using the make function */ 
map_variable = make(map[key_data_type]value_data_type)

// Determine whether the key exists in the map
// If exists=true, then value is the corresponding value
value, exists := map_variable[key]
// Delete element
delete(map_variable, key)

Recursive function

Type conversion

  1. Converts a variable of one data type to a variable of another type
  2. Implicit type conversion is not supported
// type_name is the type and expression is the expression

i := 32

//var a int32 = 3
//var b int64
//b = a
//fmt.Printf("b is:% d", b)


  1. Define keyword interface
  2. You don't have to implement all methods
/* Define interface */
type interface_name interface {
   method_name1(ps param_struct) [return_type]
   method_name2() [return_type]
   method_namen [return_type]

/* Define parameter structure */
type param_struct struct {
   /* variables */

/* Define implementation classes */
type struct_impl struct {
   /* variables */

/* Implementation interface method */
func (struct_impl_variable struct_impl) method_name1(ps param_struct) [return_type] {
   /* Method implementation */
func (struct_impl_variable struct_impl) method_namen() [return_type] {
   /* Method implementation*/

// Method call
var in interface_name
// TODO has a new keyword here
in = new(struct_impl)


// parameter
type Food struct {
	id   int
	name string
// Interface
type Animal interface {
	eat(food Food) bool
// Implementation class
type Dog struct {
	id   int32
	name string
// Method implementation
func (dog Dog) eat(food Food) bool {
	fmt.Println(dog.name, "eating", food.name)
	return true
// call
func main() {
    // Input parameter
    food := Food{
		id:   1,
		name: "Bone",
    // Method call 1 (using the new keyword to create an object fixe is equivalent to Java's parameterless construction?)
	dog1 := new(Dog)
	dog1.name = "Dog"
	dog1.id = 233
    // Method call two
	dog2 := Dog{
		id:   1,
		name: "Jacky",

error handling

  1. It provides a very simple error handling mechanism through the built-in error interface
  2. Usually, an error message is returned in the last return value of the function (which can be generated using errors.New)

reference material:

Tags: Go

Posted on Thu, 04 Nov 2021 14:54:38 -0400 by heffym