package main
import (
"fmt"
)
////////////////////////////////////////////////////////////
// Go uses escape analysis to determine that the local variable result should
// not be declared on the stack.
func twice(s string) *string {
result := s + s // result is a local variable
return &result // return a pointer to the result
}
func test1() {
fmt.Println(*twice("apple"))
fmt.Println(*twice("down"))
}
////////////////////////////////////////////////////////////
// In Go, functions can returned functions. You can also pass functions as
// parameters to functions.
func makeGreeter1() func() {
return func() {
fmt.Println("Hello!")
}
}
func test2() {
greet := makeGreeter1()
greet()
greet()
}
////////////////////////////////////////////////////////////
func makeGreeter2(s string) func() {
return func() {
fmt.Println(s)
}
}
func test3() {
greet := makeGreeter2("Hi!")
greet()
greet()
}
////////////////////////////////////////////////////////////
func makeGreeter3() func(string) {
return func(s string) {
fmt.Println(s + "!")
}
}
func test4() {
greet := makeGreeter3()
greet("Hey")
greet("Hi")
}
////////////////////////////////////////////////////////////
// makeAdder1 returns a closure, i.e. a special value that contains a function
// *and* references to the free variables that are in the function. A closure
// can be called just like a function.
func makeAdder1() func() int {
total := 0 // local variable
inc := func() int {
total++
return total
}
return inc
}
func test5() {
next := makeAdder1()
fmt.Println(next())
fmt.Println(next())
fmt.Println(next())
}
////////////////////////////////////////////////////////////
// This example shows that two closures can share the same variable.
func makeAdder2() (func() int, func() int) {
total := 0 // local variable
inc := func() int {
total++
return total
}
dec := func() int {
total--
return total
}
return inc, dec
}
func test6() {
next, prev := makeAdder2()
fmt.Println(next())
fmt.Println(prev())
fmt.Println(next())
}
////////////////////////////////////////////////////////////
func makeAdder3() (func() int, func() int, func()) {
total := 0 // local variable
inc := func() int {
total++
return total
}
dec := func() int {
total--
return total
}
reset := func() {
total = 0
}
return inc, dec, reset
}
func test7() {
next, prev, reset := makeAdder3()
fmt.Println(next())
fmt.Println(prev())
fmt.Println(next())
reset()
fmt.Println(next())
fmt.Println(prev())
fmt.Println(next())
}
////////////////////////////////////////////////////////////
// Closures are quite powerful, and could, for instance, be used to implemente
// a kind of object-oriented programming.
func makePerson(initName string, initAge int) (func(string), func() string, func(int), func() int) {
name := initName
age := initAge
setName := func(s string) {
if len(s) > 0 {
name = s
}
}
getName := func() string {
return name
}
setAge := func(n int) {
if n > 0 {
age = n
}
}
getAge := func() int {
return age
}
return setName, getName, setAge, getAge
}
func test8() {
setName, getName, setAge, getAge := makePerson("May", 11)
fmt.Printf("%v, %v\n", getName(), getAge())
setName("Irene")
setAge(getAge() + 1)
fmt.Printf("%v, %v\n", getName(), getAge())
}
////////////////////////////////////////////////////////////
func main() {
// test1()
// test2()
// test3()
// test4()
// test5()
// test6()
// test7()
test8()
}