본문 바로가기
Go

[Go] Functions

by llHoYall 2021. 10. 19.

Go also has functions.

A function is a group of codes that perform a single action.

In such a way, a function increases the reusability of code.

 

A function has its own scope.

So the variables inside a function are only used in the function.

Syntax

func FUNCTION_NAME(PARAMETER_NAME PARAMETER_TYPE, ...) [RETURN_NAME] RETURN_TYPE {
  FUNCTION_BODY
}

Here are some examples.

func sayHi() {
  fmt.Println("Hi")
}

func printString(str string) {
  fmt.Println(str)
}

func addTwoNumber(a int, b int) int {
  return a + b
}

func addTwoNumberWithError(a int, b int) (int, error) {
  if a < 0 {
    return 0, fmt.Errorf("Negative numbr is invalid: %d", a)
  }
  if b < 0 {
    return 0, fmt.Errorf("Negative numbr is invalid: %d", b)
  }
  return a + b, nil
}

If you make a function with a function name that starts with a capital letter, it will be exposed to the outside of the file.

Use Functions

sayHi()
// Hi

printString("Hello, Go")
// Hello, Go

result := addTwoNumber(2, 3)
fmt.Println(result)
// 5

result, err := addTwoNumberWithError(-2, 3)
if err != nil {
  log.Fatal(err)
}
fmt.Println(result)
// Negative numbr is invalid: -2

If you use a Function that has no parameters and no return values, just call the name of the function.

If you use a Function that has parameters and no return values, call the name of the function with arguments.

If you use a Function that has parameters and return values, call the name of the function with arguments and get the result.

That's it.

Pass-by-Value and Pass-by-Pointer

Go passes parameters as pass-by-value.

func adder(a int, b int) int {
  a = a + 1
  return a + b
}

func main() {
  a := 1
  b := 2
  c := adder(a, b)
  fmt.Println(a, c)
}
// 1 4

In the above example, we change the value of parameter a in the function, but when we check the value in the main function it doesn't change.

 

In this case, we use a pass-by-pointer.

Let's modify the example.

func adder(a *int, b *int) int {
  *a = *a + 1
  return *a + *b
}

func main() {
  a := 1
  b := 2
  c := adder(&a, &b)
  fmt.Println(a, c)
}
// 2 4

In the modified example, we pass the address of variables and change the value the address points to.

Therefore the variable in the main function is changed.

Return a Pointer Type

You can return a pointer type in functions.

func getPointerValue() *int {
  num := 3
  return &num
}

func main() {
  var getNumber *int = getPointerValue()
  fmt.Println(*getNumber)
}
// 3

Unlike other programming languages, Go can return a pointer to a local variable of the function.

A value of a variable is accessible while it is outside the scope of a function but has a pointer to that variable.

Variadic Function

A variadic function is a function that can be called with any number of arguments.

func variadicFunc(a int, b ...int) int {
  result := a
  for _, v := range b {
    result += v
  }
  return result
}

func main() {
  fmt.Println(variadicFunc(1, 2, 3, 4, 5))
}
// 15

The last parameter of the variadic function receives an arbitrary number of arguments as a Slice.

If you don't give arguments to the variadic parameter, it is handled as an empty Slice.

 

Let's see this example.

You can't give Slice to the variadic parameter.

func variadicFunc(s ...int) int {
  result := 0
  for _, v := range s {
    result += v
  }
  return result
}

func main() {
  numSlice := []int{1, 2, 3, 4, 5}
  fmt.Println(variadicFunc(numSlice))  // Error!
  fmt.Println(variadicFunc(numSlice...))  // 15
}

In this case, the ... operator spreads the values of Slice, like modern JavaScript.

Function as a Parameter

Functions in Go can be passed as arguments.

func calc(f func(int, int) int, a, b int) int {
  return f(a, b)
}

func add(a, b int) int {
  return a + b
}

func mult(a, b int) int {
  return a * b
}

func main() {
  fmt.Println(calc(add, 2, 3))
  // 5
  
  fmt.Println(calc(mult, 3, 4))
  // 12
}

Function Literal (Anonymous Function)

Function Literal are those which don't need a name to be defined.

func main() {
  func() {
    fmt.Println("Hello Go")
  }()
  // Hello Go
  
  func(v int) {
    fmt.Println(v)
  }(7)
  // 7
}

As in the example above, anonymous functions can be also called simultaneously with declarations.

 

Like other functions, anonymous functions can be assigned to variables or used as return values.

func main() {
  f := func(s string) {
    fmt.Println("Hello", s)
  }
  
  g := func(v int) func() {
    return func() {
      fmt.Println(v)
    }
  }(7)
  
  f("Go")
  // Hello Go
  
  g()
  // 7
}

 

I don't think no one will use it like this, but I'm explaining because I think it'll be good to know.

You can use the external variable in the function literal.

It is called a capture.

When capturing, the external variables are brought to pass-by-pointer.

defer in Function

If you add defer in front of a statement in the function, the statement is handled by the end of the function.

In addition, if there are multiple defer statements, it is handled by reverse order.

f, err := os.Create("test.txt")
if err != nil {
  fmt.Println("Error: Failed to create a file")
  return
}
defer f.Close()

fmt.Fprintln(f, "Hello")

Function Pointer

Go has a function pointer like C.

func add(x, y int) int {
  return x + y
}

func mult(x, y int) int {
  return x * y
}

func getFunction(op string) func(int, int) int {
  if op == "+" {
    return add
  } else if op == "*" {
    return mult
  } else {
    return nil
  }
}

func main() {
  var operator func(int, int) int
  operator = getFunction("+")
  if operator != nil {
    result := operator(1, 2)
    fmt.Println(result) // 3
  }
}

or you can simply define the function prototype like this.

type fp func(int, int) int

func getFunction(op string) fp {
  ...
}

func main() {
  var operator fp
  ...
}

It works the same.

'Go' 카테고리의 다른 글

[Go] Map  (0) 2021.10.21
[Go] Linked List  (0) 2021.10.20
[Go] Interface  (0) 2021.10.17
[Go] Method  (0) 2021.10.17
[Go] Slice  (0) 2021.10.16

댓글