한 눈에 끝내는 고랭 기초 - 3

velbie·2020년 11월 3일
0
post-thumbnail

함수

네 개의 형태로 나눌 수 있습니다.

  • 매개변수가 있고, 반환 값도 있는 형태
  • 매개변수가 있고, 반환 값이 없는 형태
  • 매개변수가 없고, 반환 값이 있는 형태
  • 매개변수가 없고, 반환 값이 없는 형태
/*기능들만 모아놓은 함수들*/
func guide() { //매개변수 X 반환 값 X
	fmt.Println("두 정수를 입력받고 곱한 결과를 출력하는 프로그램입니다.\n두 정수를 차례로 띄어 써주세요.")
	fmt.Print("두 정수를 입력해주세요 :")
}

func input() (int, int) { //매개변수 X 반환 값 O(두 개)
	var a, b int
	fmt.Scanln(&a, &b)
	return a, b
}

func multi(a, b int) int { //매개변수 O, 반환 값 O
	return a * b
}

func printResult(num int) { //매개변수 O, 반환 값 X
	fmt.Printf("결과값은 %d입니다. 프로그램을 종료합니다.\n", num)
}
  • 지역변수: 지역변수는 해당 지역에서 선언되는 순간 메모리가 생성되고 해당 지역을 벗어나면 자동으로 소멸됩니다.
  • 전역변수는: 전역변수는 코드를 복잡하게 만들고 메모리를 끝날때까지 차지하고 있습니다.
    고언어 함수의 매개변수는 지역변수or전역변수? Pass by value or Pass by reference?

Pass by value 일반적인거 (다른언어와 동일)

package main

import "fmt"

func printSqure(a int) {
	a *= a
		
	fmt.Println(a)
}
func main() {
	a := 4 //지역변수 선언
		
	printSqure(a)
		
	fmt.Println(a)
}

Go 는 포인터를 지원하기 때문에 Pass by reference

package main

import "fmt"

func printSqure(a *int) {
	*a *= *a
	
	fmt.Println(*a)
}
func main() {
	a := 4         //지역변수 선언
	
	printSqure(&a) //참조를 위한 a의 주솟값을 매개변수로 전달
	
	fmt.Println(a)
}

가변인자 함수

  • 사실상 슬라이스 전달방법
  • n개의 동일한 형의 매개변수를 전달합니다.
  • 전달된 변수들은 슬라이스 형태입니다. 변수를 다룰 때 슬라이스를 다루는 방법과 동일합니다.
  • 함수를 선언은 "func 함수이름(매개변수이름 ...매개변수형) 반환형" 형식으로 합니다. '매개변수형' 앞에 '...'을 붙이면 됩니다.
  • 매개변수로 슬라이스를 전달할 수 있습니다. 다른 컬렉션 형태는 불가능합니다. 슬라이스를 전달할 때는 슬라이스 이름 뒤에 ...를 붙여서 "함수이름(슬라이스이름...)" 형식으로 함수를 호출하면 됩니다.
    사용법
package main

import "fmt"

func addOne(num ...int) int {
	var result int

	for i := 0; i < len(num); i++ { //for문을 이용한 num[i] 순차 접근
		result += num[i]
	}
	
	return result
}

func addTwo(num ...int) int {
	var result int

	for _, val := range num { //for range문을 이용한 num의 value 순차 접근
		result += val
	}
	
	return result
}

func main() {
	num1, num2, num3, num4, num5 := 1, 2, 3, 4, 5
	nums := []int{10, 20, 30, 40}

	fmt.Println(addOne(num1, num2))
	fmt.Println(addOne(num1, num2, num4))
	fmt.Println(addOne(nums...))
	fmt.Println(addTwo(num3, num4, num5))
	fmt.Println(addTwo(num1, num3, num4, num5))
	fmt.Println(addTwo(nums...))
}

반환값

Go 언어에서는 복수개의 반환값을 반환할 수 있다는 것입니다.
반환값는 수 만큼 반환타입을 모두 명시해야합니다.

package main

import "fmt"

func add(num ...int) (int, int) {
	var result int
	var count int
	
	for i := 0; i < len(num); i++ { //for문을 이용한 num[i] 순차 접근
		result += num[i]
		count++
	}
	
	return result, count
}

func main() {
	nums := []int{10, 20, 30, 40, 50}

	fmt.Println(add(nums...))
}

Named Return Parameter

반환 타입만 적었는데, 변수명과 타입을 같이 적어주는 기법입니다.
따로 선언할 필요 없습니다.
return은 생략하면 안됩니다.

func dessertList(fruit ...string) (count int, list []string) { //여기서 이미 선언된 것이다

	...

	return //생략하면 안 된다
}

익명 함수

익명 함수는 좀 독특합니다.

  • 함수를 선언하면 전역으로 초기화 되면서 메모리를 잡아먹습니다.
  • 기능을 수행할 때마다 함수를 찾아서 호출해야하기 때문입니다.
package main

import "fmt"

func main() {
	func() {
		fmt.Println("hello")
	}()

	func(a int, b int) {
		result := a + b
		fmt.Println(result)
	}(1, 3)

	result := func(a string, b string) string {
		return a + b
	}("hello", " world!")
	fmt.Println(result)

	i, j := 10.2, 20.4
	divide := func(a float64, b float64) float64 {
		return i / j
	}(i, j)
	fmt.Println(divide)
}

보면 선언과 동시에 실행하고 있습니다.
저 위에서 함수 반환값과 이름을 선언해서 변수처럼 사용하고 return 만하는 Named Return Parameter 를 배웠는데 익명함수에서도 비슷한 기능이 있습니다.
다만 변수에 초기화한 익명 함수는 변수 이름을 함수의 이름처럼 사용할 수 있다는 것 입니다.

addAnonymous := func(nums ...int) (result int) {
		for i := 0; i < len(nums); i++ {
			result += nums[i]
		}
		return
	}

이렇게 사용합니다. 근데 결국 선언함수와 똑같아지는데..흠..
선언함수와 익명함수는 프로그램 내부적으로 읽는 순서가 다릅니다. 선언함수는 프로그램이 시작됨과 동시에 모두 읽습니다. 하지만 익명 함수는 위 예시들처럼 그 자리에서 실행되기 때문에 해당 함수가 실행되는 곳에서 읽습니다. 즉, 선언함수보다 익명 함수가 나중에 읽힙니다. 그래서 만약 선언함수와 익명함수가 이름이 같으면 익명함수가 선언함수를 덮어씁니다. 지역변수와 전역변수의 차이점과 같습니다.

package main

import "fmt"

func add() {
	fmt.Println("선언 함수를 호출했습니다.")
}

func main() {

	add := func() {
		fmt.Println("익명 함수를 호출했습니다.")
	}

	add()
}

일급 함수(First-Class Function)

익명 함수의 사용은 Go언어에서 함수가 '일급 함수' 이기 때문에 가능한 것입니다.
함수는 다른 타입들과 비교했을 때 높은 수준의 용법이 아니라 같은 객체로서 사용될 수 있습니다.
함수자체를 인자로 넘길 수 있습니다. (아래 코드 확인)

package main

import "fmt"
//    3. 그럼 매개변수에 다 적어줘야함 (<- 귀찮)
func calc(f func(int, int) int, a int, b int) int {
	result := f(a, b)
	return result
}

func main() {
	// 1. 멀티라는 함수를 만들고
	multi := func(i int, j int) int {
		return i * j
	}
	// 2. calc 함수로 넘김
	r1 := calc(multi, 10, 20)
	fmt.Println(r1)
}

type문을 사용한 함수 원형 정의

위에 코드에서 3.번을 보면 가독성도 떨어지고 번거롭다는 것을 알수 있습니다.
그래서 'type' 문을 사용해 함수의 원형을 정의하고 사용자가 정의한 이름을 사용합니다.
c 의 구조체 개념과 유사합니다. (구조체 이름 만들고 .. 그랬던 기억이..)

//1. 함수 원형 정의
type calculatorNum func(int, int) int 

// 4. 함수 선언에 함수 원형정의가 되어있어서 가독성이 좋아졌습니다.
func calNum(f calculatorNum, a int, b int) int {
	result := f(a, b)
	return result
}

func main() {
	// 2. 익명함수, 맨위에 함수원형 정의가 되어있습니다.
	multi := func(i int, j int) int {
		return i * j
	}
    
    // 3. 넘깁니다.
	r1 := calNum(multi, 10, 20)
	fmt.Println(r1)
}
profile
안녕하세요

0개의 댓글

관련 채용 정보