Defining Simple Functions ========================= A Go_ function consists of a **signature** (or **header**) followed by a block of code that will be executed when the function is called. Here's a function that prints a greeting message:: func hello(name string) { // function signature fmt.Println("Hello " + name + "!") // function body } // Calling hello("Dave") prints: Hello Dave! This function's name is ``hello``, and it takes a single parameter of type ``string`` called ``name``. Notice that the name of a parameter comes first, followed by its data type. It prints a message to the screen without returning a value. In Go_, function parameters are **always passed by value**. For example, calling ``f(x)`` means that the value of ``x`` is copied. Thus, you cannot modify the value of ``x``, and, if ``x`` is big, the copying takes extra time and space. Consider this function for calculating the area of a rectangle:: func rect_area(width, height int) int { // function signature return width * height // function body } // rect_area(10, 5) returns 50 ``rect_area`` takes two ``int`` parameters, ``width`` and ``height``. It also returns an ``int``: the ``return`` statement is used to end the function and return a value. You could also have written the function with a slightly different header like this:: func rect_area(width int, height int) int { return width * height } Here's a function that counts the number of *e* s in a string:: func ecount(s string) int { result := 0 for _, c := range s { if c == 'e' || c == 'E' { result++ } } return result } As before, a ``return`` statement ends a function and returns a value. Another way to write this function is with a **named result parameter**, e.g.:: func ecount(s string) (result int) { // result is initialized to 0 for _, c := range s { if c == 'e' || c == 'E' { result++ } } return // no need to mention result here } Functions can also return multiple values. A common use case for this is to return a value and an error flag. For instance:: func ecountFile(fname string) (int, error) { // note two return types bytes, err := ioutil.ReadFile(fname) // bytes is a byte slice result := 0 if err == nil { // err is nil when file for _, c := range bytes { // is read correctly if c == 'e' || c == 'E' { result++ } } } return result, err } Note that ``error`` is a built-in type, and ``ioutil.ReadFile`` is a convenience function that reads an entire file from disk into a slice of bytes. Of course, if the file is very large, this could cause memory problems. You call ``ecountFile`` like this:: count, err := ecountFile("funcs.txt") if err == nil { fmt.Println(count) } It's up to the programmer to check the error flag. We could also have written ``ecountFile`` with named result parameters:: func ecountFile(fname string) (result int, err error) { // named results bytes, err := ioutil.ReadFile(fname) if err == nil { for _, c := range bytes { if c == 'e' || c == 'E' { result++ } } } return } Questions --------- #. What technique is used to pass parameters in Go_ functions? #. *True* or *false*: every Go_ function must have an explicit type for its return value. For functions that don't return a value, the return type is ``void``. #. *True* or *false*: when a Go_ function returns more than one value, the values must be of the same type. #. *True* or *false*: Go_ lets you use both multiple return values and named result parameters in the same function.