Lesson 8
Using Functions

Functions are an important aspect of any programming language in that they allow us to create reusable blocks of code that can use a variety of input values. You've used functions in previous lessons, including the functions main and Println. In this lesson, you will take a closer look at functions and learn to create your own.

DEFINING A FUNCTION

A function is a block of organized, reusable code that uses one or more Go statements to complete a single, related action. You use functions to help with code reusability, increased readability, and redundancy checking (making sure that you do not use the same lines over and over within an application).

Go provides many built-in functions, such as the fmt.Println() function that you've been using throughout this book; however, you are also allowed to create or define your own functions. A function that you define yourself in a Go program is known as a user-defined function.

As you progress through this lesson, here are a few key terms you should know:

  • Functions are blocks of organized, reusable code.
  • User-defined functions are functions defined by the user. These functions use the def keyword to define them.
  • Built-in functions are functions that are built into Go.
  • Arguments are pieces of information passed into functions. An argument is the value sent to the function when called upon.

Functions allow you to organize snippets of code that can then be used (called) to perform specific functionality. One of the core values of functions is that you can write the code once and then call it as many times as you would like.

You define a function using the keyword func, and you can define any values you need for the function as parameters of that function. The basic syntax to define a function is:

func funcName (arg1 type, arg2 type) returnType {
    [function instructions]
}

A function can take zero or more parameters, depending on what you want it to do, so it is possible to define a function without any parameters at all, as in main(). Let's look at a simple function that adds two numbers. A function called add is presented in Listing 8.1.

There are two areas of Listing 8.1 that are worth a close look. First is the definition of the add function. You see this definition starting with the func keyword, followed by the name of the new function being defined, add. You then see that the function has two parameters called a and b that are both defined as type int. At the end of the function declaration line, you see that the type of int is listed, which means that the add function is expecting to return an integer value.

The body of the add function is contained between a set of brackets ({}). In the case of the add function, the body is only a single line of code:

return a + b

This simple line of code adds the values that are in a and b and returns the result. Note that a and b are parameters, so they are expected to be provided when the add function is called. Similarly, the return statement returns the result of the addition to the code that called the function.

In fact, you can see that the add function is called from within the Println function that is in the main function of the listing. As expected, you can also see that the values of 4 and 6 are passed as arguments to the function. The returned value from the call to add is then used within the Println statement. The resulting output is:

add function results: 10

Note that the add function is created outside the main function. This makes it a global function that can be accessed from inside the main function or from anywhere else within our program listing.

Using Multiple Functions

A program can include multiple functions, and you can use the same values in multiple functions. Listing 8.2 is a variation of the previous program, with a simplified add2 function and a new multiply function.

When you execute this program, the following output is displayed:

c = 5
d = 6
add result: 11
add2 result: 11
multiply result: 30

In this case, the add2 function has a simpler signature than the original add function. Specifically, you use (a, b int) to define the function's parameters. You can do this only because both parameters are of the same type. If the function used parameters of different types, you would have to use the syntax in the add function.

You also use variables instead of hard-coded values in the main function. This allows you to easily reuse the numbers in multiple functions. Here, you used the values of c and d in each of the functions.

Functions with No Return Values

In the functions created in the previous two listings, you returned a single calculated value. You don't have to return a value in a function, especially if the function provides output already.

In Listing 8.3, the function converts a string to uppercase and prints the results as part of the function. Note that the listing includes the package called strings, which contains functions you'll use in the new function being created.

In this listing a new function called DisplayUpper is created that takes a string called x. You can see that there is no return type listed after the parameter, so nothing is expected to be returned. The function itself simply prints the original text, then uses the ToUpper function in the strings package to convert the string to uppercase. When this listing is executed, the following output should be displayed:

Original text: elizabeth
Revised text: ELIZABETH

You can change the value of a from elizabeth to any other string and run the program again. You can also pass a string literal to our new function to convert it as well.

Functions with Multiple Return Values

You've now seen how to return a single value from a function as well as how to create a function that does not return a value. You can also create functions that return multiple values.

To return a single value, you include the returned data type in the function declaration:

func funcName (arg1 type, arg2 type) returnType {

In this case, returnType is the type of the data to be returned. To return more than one value, you can place each of the return types in parentheses separated by a comma:

func funcName (arg1 type, arg2 type) (returnType, …, returnType) {

The created function will then need to return all the values with the return statement. Each value should be separated by a comma, as shown in Listing 8.4.

While this is not the best application of using a function, it provides a simple illustration of returning multiple values. The function rectStuff is declared to receive two arguments (length and width). More importantly, it also returns two integer values. Looking within the function, you can see that two variables are declared and assigned values determined based on what was passed to the function. Calculations are performed and the results are assigned to the variables a and c. A single return statement then returns both of these values back to the calling function.

Looking in the main function, you can see that the rectStuff function is called with the two arguments of 3 and 5. To the left of the assignment operator, you see that there are two variables separated by a comma that are ready to receive the two integer values that will be returned.

When this listing is executed, the following output should be displayed:

area: 15
perimeter: 16

Returning Different Types

When returning multiple values from a function, it is not mandatory that they be the same. In Listing 8.4, both data types were of type int. You could use other data types as well. The important thing is that you must return values of the types you indicate. Listing 8.5 presents a function that returns two different data types.

This time, instead of determining characteristics of a rectangle, the listing determines a diameter and circumference of a circle. Looking at the circleStuff function details, you can see that a value of type int and a value of type float32 are returned, in that order. The function itself simply calculates the diameter (d) and the circumference (c) and then returns the results in a single return statement. You should note that because you are calculating a floating-point number using an integer, you do need to use a cast function on the radius to avoid a type mismatch error. The results of running this listing when passing a radius of 5 are:

Diameter: 10
Circumference: 31.400002

Returning Named Types

In Go you can also define the names of the return values. In Listing 8.6, the circleStuff function has been rewritten to use named return values.

When the return values are named, those names are then usable within the function. You can see in the listing that the circleStuff function returns two values, one of type int and one of type float32. More importantly, you can see that each return value is given a name prior to the type. The return variable d is defined as the int, and the return variable c is defined as the float32. You are also using math.Pi instead of 3.14, so your output will be more accurate.

Within the code, values are assigned to these return variables. Because the return variables have already been identified, there is no need to list them after the return statement. The output from running Listing 8.6 is similar to the previous listing:

Diameter: 10
Circumference: 31.415928

Skipping a Return Value

When calling a function that returns multiple values, you have the option to skip the use of some of the values. In fact, you can use the blank identifier (_) to indicate you do not need a value returned. Listing 8.7 is a modification of Listing 8.6. In this case, only the diameter is needed, so the circumference is skipped.

When you run this listing, the output is

diameter: 10

Notice that within the main function, the blank identifier was used instead of a variable for circumference. This allowed the diameter to be retrieved without getting the circumference.

You might wonder why you don't simply include a placeholder variable when you call the listing. The reason is because Go will give an error if you declare a variable and don't use it.

VARIADIC FUNCTIONS

In general, functions are designed to accept a fixed number of parameters, but there are cases where you may not know ahead of time how many parameters you need, especially if you are working with data structures like arrays and maps that can be of different lengths. When you're using a variadic function (a function with a variable number of parameters), all parameter values must be of the same type. You define the parameter using this syntax:

func funcName (parameterNametype) [returnType] {
    // function instructions
}

Listing 8.8 presents a function called sumN that accepts a variable number of inputs. The function adds the values of all the arguments received and returns the sum.

The output is

Current element: 4 ; Current index: 0
Current element: 6 ; Current index: 1
Current element: 5 ; Current index: 2
Sum of values: 15
Current element: 4 ; Current index: 0
Current element: 6 ; Current index: 1
Current element: 5 ; Current index: 2
Current element: 6 ; Current index: 3
Current element: 7 ; Current index: 4
Current element: 8 ; Current index: 5
Sum of values: 36

In this example, the sumN function accepts a range of values rather than a fixed number of values, and it returns no value. It includes a for loop that uses range to iterate through the values provided, adding each value to the current total, printing each value and its index number as it cycles through the loop.

Finally, it prints the sum of the numbers provided when the function is called. In the first case, it has only three numbers to work with, but in the second case, it has six numbers.

RECURSION

Go also supports recursive functions. A recursive function is one that calls itself. Listing 8.9 shows one of the most common uses of recursion, which is calculating the factorial of a given number.

In this example, you create a function named factorial, and this function calls itself in the process of calculating the factorial of a given number. Looking closer, you can see that the function receives an integer. If that integer is 0, then the value of 1 is returned. If the number passed to the function is not 0, then the function is called again when the return statement is executed.

The main function passes the value of 5 to the factorial function. The resulting output is the number 120.

FUNCTION AS A VALUE

In Go, you can assign a function to a variable and then reference the variable when the function is needed. In Listing 8.10, you use the circleStuff function described earlier, but this time, instead of defining the function outside of the main function, you create a variable named circleStuff and assign the function to that variable.

This program works identically to the earlier version, with exactly the same output:

10 31.415928

Once you define the variable, you can use it to reference the function anywhere in the main function.

CLOSURES

Go supports anonymous functions. An anonymous function is a function that does not have a name. In some cases, you simply want the function to run once as part of the main program; you don't need to name it because you don't plan to reuse it. Alternatively, you can assign the anonymous function to a variable or use it as part of a larger function and then call the function through the variable or parent function instead of calling it directly.

A closure is a special type of anonymous function that references variables declared outside of the function itself. In a normal function, you use either constants or variables in the main program and pass those values to the parameters defined in the function. The function itself uses its own parameters as the variables.

In a closure, however, you simply reuse the variables you initialized elsewhere and call them directly in the closure. As an example (see Listing 8.11), let's go back to the simple add function you used earlier and use it as an anonymous function.

In this program, you create an anonymous function that adds two values, and you assign the function to a variable. The function itself is a closure because it calls the variables defined in the main function, and it does not have any defined parameters of its own.

You use the variable add to call the function. Because the function already knows what values to use, you do not need to provide those values when you call the function.

Listing 8.12 includes a closure as part of the passGenerator function.

The passGenerator function is configured to generate a password using a series of randomly generated characters. The resulting password is saved to the pwd variable, a variable that is defined outside of the anonymous function that generates the password.

SUMMARY

In this lesson you learned about one of the important features for organizing your code. As you write programs using Go, it is important to organize functionality. You can do so with functions.

Not only did you learn how to create your own functions, but you also learned how to pass items to a function in a variety of ways as well as how to return and receive information from the functions you create. The lesson ended by covering a couple of more advanced topics, including recursion, assigning a function to a variable, and closures.

In the next lesson, you'll start to dig into special data structures that can be used to hold information. You will be learning about arrays!

EXERCISES

The following exercises are provided to allow you to experiment with the tools and concepts presented in this lesson. For each exercise, write a program that meets the specified requirements and verify that the program runs as expected. The exercises are:

Exercise 8.1: Creating Your Own Functions

Write a program that uses at least two customized functions to perform operations on at least two values input by the user. As an example, you could create a function that compares an input value to a fixed value to determine if the values are the same. As a more complicated approach, you could create a login function that compares an input username and password to a known username and password and displays appropriate feedback based on whether or not both input values match the known values.

Exercise 8.2: Spheres

Rename the circleStuff function presented in the lesson to sphereStuff. Modify the function to also return the area of the sphere in addition to the circumference and diameter.

Exercise 8.3: What Does the Fox Say?

Create a new function called petSound. The function should take the name of a pet as the parameter. The function should return a string that indicates the sound the pet makes.

For example, if the function were called with dog in the following manner:

fmt.Println("A dog says", petSound("dog"))

then, the return value would be woof and the output would be

A dog says woof

Exercise 8.4: Using Recursion

Research other problems that can use recursion to find the solution. Write a program that includes a recursive function for at least two other examples.

Exercise 8.5: Fibonacci Function

Implement a Fibonacci function that returns a function (a closure) that returns successive Fibonacci numbers (0, 1, 1, 2, 3, 5, …).

Exercise 8.6: A Calculator

Create a calculator application that runs from the command line. The calculator should perform the following tasks:

  • Accept a word like quit or exit at any prompt to end the program.
  • Accept two numeric values from the user.
  • Allow the user to choose a mathematical operation using the two input values, including at least addition, subtraction, multiplication, modulus (%), square root, and factorial. You may include other operations if you wish.
  • Display the output as a complete mathematical statement. For example, if the user wants to add two numbers, the output should look like
    8 + 9 = 17
    
  • Prompt the user to start over after completing a calculation.

Additional requirements:

  • Use and call appropriate functions in the code.
    • Each operation should be a separate function.
    • Include additional functions as appropriate.
  • If the user enters an unexpected/invalid value at a prompt or the output causes an error (such as dividing by 0), the program should display appropriate feedback and prompt the user to try again.
  • The program should be as user-friendly as possible, by giving the user clear options for each prompt and letting them know how to exit the program when they wish.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset