This is the 26th day of my participation in the August More Text Challenge.

function

Function to solve

Over the last four lessons, you’ve seen a very important function in Go: the main function, which is an entry function to Go programs, and I’ll use it over and over again as I demonstrate code examples.

Here is an example of a main function:

func main() {

}
Copy the code

It consists of the following parts:

  1. Any function definition has a func keyword that is used to declare a function, just as the var keyword is used to declare a variable;
  2. “Main” is the name of the function, which conforms to the Go specification.
  3. The parentheses () after the main function name cannot be omitted. The parentheses can define the parameters used by the function.
  4. You can also have the return value of the function after the parenthesis (), because main does not return a value, so it is not defined here;
  5. Finally, there is the body of the curly braces {} function, where you can write code and write the function’s own business logic.

Function declaration

After the introduction of the previous section, I believe you have a clear understanding of the constitution of the Go language functions. Now let’s summarize the declaration format of the function, as shown in the following code:

func funcName(params) result {

    body

}
Copy the code

This is the signature definition of a function, which contains the following parts:

  1. Keywords func;
  2. Function name funcName;
  3. The parameter params, which defines the variable names and types of the parameters, can have one, multiple, or none;
  4. Result is the return value of the function, which defines the type of the return value. If there is no return value, omit it or have more than one return value.
  5. The body is the body of the function, where you can write the code logic of the function.

Now, let’s create a custom function based on the above function declaration format, as follows:

func sum(a int,b int) int{

    return a+b

}
Copy the code

This is a function that evaluates the sum of two numbers. The function is called sum and takes two arguments, a and b, both of type int. The sum function returns an int. The body of the function is the sum of a and b, and the return keyword is used. If the function does not return a value, the return keyword is omitted.

Finally, you can declare your own function. Congratulations!

The definition of a parameter in a function is the same as that of a variable. The name of the variable comes first and the type of the variable comes second, but in a function, the name of the variable is called the parameter name, which is the parameter of the function. The parameter can only be used inside the function. The value of the function parameter is supplied by the caller. This value is also called the argument to the function. Now we pass the argument to sum to demonstrate the call to the function, as shown in the following code:

Func main() {result:=sum(1,2) fmt.println (result)}Copy the code

Our custom sum function is called directly from the main function with real arguments, namely arguments 1 and 2.

The return value of the function is assigned to the variable result, which is then printed out. If you run this for yourself, you can see that the result is 3, so we can use the sum function to add two numbers. If other business logic also needs to add two numbers, we can use the sum function without defining it.

In the above function definition, the type of the a and b parameters is the same, so we can omit either type declaration as follows:

func sum(a, b int) int {

    return a + b

}
Copy the code

Using a comma separating a variable like this, followed by an int, is the same as declaring a variable. Multiple variables of the same type can be declared this way.

More value is returned

Unlike some programming languages, the Go language functions can return multiple values, that is, multiple value returns. In the Go standard library, you can see a lot of functions where the first value returns the result of the function and the second value returns the error message. This is a classic use of multi-value returns.

For the sum function, assuming that we are not allowed to provide negative arguments, we can modify it by returning multiple values if the argument is negative, as shown in the following code:

Func sum (int a, b) (int, error) {if a < 0 | | b < 0 {return 0, errors. The New (" a or b can't be negative ")} return a + b, nil}Copy the code

Note here that if a function returns multiple values, the type definition of the return value part needs to be enclosed in parentheses, i.e. (int,error). This means that sum returns two values. The first one is an int and the second one is an error. This is also the order in which we return the result from the function body.

In the body of a function, you can use return to return multiple values separated by commas (,) in the same order as the return type of the function declaration, as in the following example:

Return 0,errors.New(" A or b cannot be negative ")Copy the code

The first value returned, 0, is of type int, and the second value is of type error, exactly the same as the return type defined by the function.

methods

Different from the method of a function

In Go, methods and functions are two very similar concepts, but the difference is that methods must have a receiver, and that receiver is a type, so that methods are bound to that type, called methods of that type.

In the following example, type Age uint means to define a new type Age, which is equivalent to uint and can be understood as a rename of the type uint. Type is the Go keyword, which defines a type.

type Age uint

func (age Age) String(){

    fmt.Println("the age is",age)

}
Copy the code

In the example, the method String() is a method of type Age, which is the receiver of the method String().

Unlike functions, methods are defined with an age age between the keyword func and the method name String, surrounded by parentheses.

The receiver is defined like a normal variable, function parameter, etc., preceded by the variable name and followed by the receiver type.

Now the method String() is bound to the type Age. String() is a method of type Age.

Once the receiver’s method is defined, the method can be invoked via the dot operator, as shown in the following code:

func main() {

    age:=Age(25)

    age.String()

}
Copy the code

Run this code and you should see the following output:

the age is 25
Copy the code

Receivers are the biggest difference between functions and methods, and methods have all the capabilities mentioned above.

Tip: Because 25 is also of unit type, the unit type is equivalent to the Age type I defined, so 25 can be cast to Age.

Value type receiver and pointer type receiver

The recipient of a method can be either a value type (as in the example in the previous section) or a pointer type.

The recipient type of the defined method is a pointer, so our changes to the pointer are valid. If it is not a pointer, the changes have no effect, as follows:

func (age *Age) Modify(){

    *age = Age(30)

}
Copy the code

After calling the Modify method once and then calling the String method to check the result, you will find that the result has changed to 30, indicating that the cursor-based modification is effective, as shown below:

age:=Age(25)

age.String()

age.Modify()

age.String()
Copy the code

Tip: When a method is called, the recipient of the pass is essentially a copy, but a copy of the value and a copy of the pointer to the value. Pointers have the property of pointing to the original value, so if you change the value to which the pointer points, you also change the original value. We can simply understand that the value receiver invokes the method using a copy of the value, while the pointer receiver invokes the method using the actual value.

In this example, the pointer receiver method is called with a value variable, not a pointer type, but it can be called with a pointer variable, as shown in the following code:

(&age).Modify()
Copy the code

This is what the Go compiler automatically does for us:

  • If a value type variable is used to call a pointer type receiver’s method, the Go language compiler automatically takes the pointer call for us to satisfy the pointer type receiver.
  • Similarly, if a pointer type variable is used to call a value type receiver’s method, the Go compiler will automatically dereference the call to satisfy the value type receiver.

In short, method callers can be either values or Pointers, do not pay too much attention to these, Go language will help us automatically escape, greatly improve the development efficiency, while avoiding bugs caused by carelessness.

Whether you use a value type receiver or a pointer type receiver, determine your requirements first: do you want to change the value of the current receiver when operating on the type, or do you want to create a new value and return it? These can determine which recipient to use.