Passing parameter values

In Go, all parameters passed to a function are done so by value. This means a local copy of the passed values is created inside the called function. There is no inherent concept of passing parameter values by reference. The following code illustrates this mechanism by modifying the value of the passed parameter, val, inside the dbl function:

package main 
import ( 
   "fmt" 
   "math" 
) 
 
func dbl(val float64) { 
   val = 2 * val // update param 
   fmt.Printf("dbl()=%.5f
", val) 
} 
 
func main() { 
   p := math.Pi 
   fmt.Printf("before dbl() p = %.5f
", p) 
   dbl(p) 
   fmt.Printf("after dbl() p = %.5f
", p) 
} 

golang.fyi/ch05/funcpassbyval.go

When the program runs, it produces the following output that chronicles the state of the p variable before it is passed to the dbl function. The update is made locally to the passed parameter variable inside the dbl function, and lastly the value of the p variable after the dbl function is called:

$> go run funcpassbyval.go
before dbl() p = 3.14159
dbl()=6.28319
after dbl() p = 3.14159

The preceding output shows that the original value assigned to variable p remains variable unchanged, even after it is passed to a function that seems to update its value internally. This is because the val parameter in the dbl function receives a local copy of the passed parameter.

Achieving pass-by-reference

While the pass-by-value is appropriate in many cases, it is important to note that Go can achieve pass-by-reference semantics using pointer parameter values. This allows a called function to reach outside of its lexical scope and change the value stored at the location referenced by the pointer parameter as is done in the half function in the following example:

package main 
import "fmt" 
 
func half(val *float64) { 
   fmt.Printf("call half(%f)
", *val) 
   *val = *val / 2 
} 
 
func main() { 
   num := 2.807770 
   fmt.Printf("num=%f
", num) 
   half(&num) 
   fmt.Printf("half(num)=%f
", num) 
} 

golang.fyi/ch05/funcpassbyref.go

In the previous example, the call to the half(&num) function in main() updates, in place, the original value referenced by its num parameter. So, when the code is executed, it shows the original value of num and its value after the call to the half function:

$> go run funcpassbyref.go
num=2.807770
call half(2.807770)
half(num)=1.403885

As was stated earlier, Go function parameters are passed by value. This is true even when the function takes a pointer value as its parameter. Go still creates and passes in a local copy of the pointer value. In the previous example, the half function receives a copy of the pointer value it receives via the val parameter. The code uses pointer operator (*) to dereference and manipulate, in place, the value referenced by val. When the half function exits and goes out of scope, its changes are accessible by calling the main function.

Anonymous Functions and Closures

Functions can be written as literals without a named identifier. These are known as anonymous functions and can be assigned to a variable to be invoked later as shown in the following example:

package main 
import "fmt" 
 
var ( 
   mul = func(op0, op1 int) int { 
         return op0 * op1 
   } 
 
   sqr = func(val int) int { 
         return mul(val, val) 
   } 
) 
 
func main() { 
   fmt.Printf("mul(25,7) = %d
", mul(25, 7)) 
   fmt.Printf("sqr(13) = %d
", sqr(13)) 
}  

golang.fyi/ch05/funcs.go

The previous program shows two anonymous functions declared and bound to the mul and sqr variables. In both cases, the functions take in parameters and return a value. Later in main(), the variables are used to invoke the function code bound to them.

Invoking anonymous function literals

It is worth noting that an anonymous function does not have to be bound to an identifier. The function literal can be evaluated, in place, as an expression that returns the function's result. This is done by ending the function literal with a list of argument values, enclosed in parentheses, as shown in the following program:

package main 
import "fmt" 
 
func main() { 
   fmt.Printf( 
         "94 (°F) = %.2f (°C)
", 
         func(f float64) float64 { 
               return (f - 32.0) * (5.0 / 9.0) 
         }(94), 
   ) 
} 

golang.fyi/ch05/funcs.go

The literal format not only defines the anonymous function, but also invokes it. For instance, in the following snippet (from the previous program), the anonymous function literal is nested as a parameter to fmt.Printf(). The function itself is defined to accept a parameter and returns a value of type float64.

fmt.Printf( 
   "94 (°F) = %.2f (°C)
", 
   func(f float64) float64 { 
         return (f - 32.0) * (5.0 / 9.0) 
   }(94), 
) 

Since the function literal ends with a parameter list enclosed within parentheses, the function is invoked as an expression.

Closures

Go function literals are closures. This means they have lexical visibility to non-local variables declared outside of their enclosing code block. The following example illustrates this fact:

package main 
import ( 
   "fmt" 
   "math" 
) 
 
func main() { 
   for i := 0.0; i < 360.0; i += 45.0 { 
         rad := func() float64 { 
               return i * math.Pi / 180 
         }() 
         fmt.Printf("%.2f Deg = %.2f Rad
", i, rad) 
   } 
} 

github.com/vladimirvivien/learning-go/ch05/funcs.go

In the previous program, the function literal code block, func() float64 {return deg * math.Pi / 180}(), is defined as an expression that converts degrees to radians. With each iteration of the loop, a closure is formed between the enclosed function literal and the outer non-local variable, i. This provides a simpler idiom where the function naturally accesses non-local values without resorting to other means such as pointers.

Note

In Go, lexically closed values can remain bounded to their closures long after the outer function that created the closure has gone out of scope. The garbage collector will handle cleanups as these closed values become unbounded.

..................Content has been hidden....................

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