반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- newSQL
- kernel
- DBMS 개발
- 한빛미디어
- 커널
- 약어
- Pointer
- OS 커널
- getopts
- TiDB
- go
- bash
- TiKV
- 컴퓨터 강좌
- 전처리기
- Programming
- Symbol
- FreeBSD
- Golang
- 구조와 원리
- 함수포인터
- Preprocessor
- SQLite
- UNIX Internals
- DBMS
- 포인터
- 긴옵션
- 포인터변수
- UNIX
- Windows via c/c++
Archives
- Today
- Total
sonumb
Go - 다차원 배열을 파라미터로 받을 때 본문
개요
결론을 말하자면, '다차원 배열'을 '참조에의한호출'로 다른 함수에서 참조할 수 있다.
그러나, 배열 대신 슬라이스를 이용하는 것을 가장 추천한다. (코드가 간단해지므로)
다차원 배열을 선언할 때, var arr [5][2]int
처럼 배열 크기를 명시하거나,var arr [...][2]int
와 같이 ...
을 기입해주어 해야 배열로 선언되고,
var sliece [][2]int
와 같이 크기가 없거나,slice := make([][2]int, 0)
와 같이 make()
를 호출해야 슬라이스로 선언된다.
그렇다면, 다차원 배열을 함수에 인자값으로 넘길 때, call-by-reference를 하고 싶다면?
참고로, C 언어 같은 경우
void foo( int arr[][2] );
// 혹은
void bar( int (*arr)[2] );
처럼 선언해야, 콜바이 레퍼런스가 된다.
결론적으로, Go에서는 C언어의 첫번째 방법과 동일하게 파라미터를 정의하면 된다.
func foo( arr [][2]int ) {
// blah
}
아래와 같이 '...' 키워드(?)를 이용해도 된다.
func bar( arr ...[2]int ) {
// blah
}
다만, bar()
함수 호출할 때 유의점이 있다.
일단, 아래와 같이 두 가지 방법이 존재한다.
...
을 이용한 호출- 개별적으로 값을 넘긴 호출
결론만 말하자면, 둘의 차이는 call-by-ref, call-by-value 와 같다.
func main() {
a := [5][2]int {
{1, 2},
{3, 4},
}
foo(a[:])
bar(a[:]...)
bar(a[0], a[1])
}
아래 소스코드와 이의 결과를 확인해 볼 것.
그리고 위 함수를 호출할때, 슬라이스와 배열 모두 처리가능 하다. (어떤 원리인지 궁금하다. 아시는 분?)
소스코드
package main
import (
"fmt"
)
func call_by_pointer(elem *[5][2]int) {
for i:=0; i< len(elem) ;i++ {
elem[i][0] += 10
}
}
func call_by_slice(elem [][2]int) {
for i:=0; i< len(elem) ;i++ {
elem[i][0] += 10
}
}
func call_by_slice2(elem [][]int) {
for i:=0; i< len(elem) ;i++ {
elem[i][0] += 10
}
}
func call_by_dots(elem ...[2]int) {
for i:=0; i< len(elem) ;i++ {
elem[i][0] += 10
}
}
func call_by_dots2(elem ...[]int) {
for i:=0; i< len(elem) ;i++ {
elem[i][0] += 10
}
}
func main() {
fmt.Println("-------- array ----------------------------------------------------")
a1 := [...][2]int{ // [5][2]int
{11, 1},
{12, 1},
{13, 1},
{14, 1},
{15, 1},
}
fmt.Printf("%-*s:%+v\n", 30, "original array 1", a1)
// foo(a ... T)의 a에 foo(a1[0], a[1]) 으로 넘겨주면, 포인터가 아니라 [2]int{1,2}와 같은 값이 넘어간다.
call_by_dots(a1[0], a1[2], a1[3], a1[4]) // call by value 다. reference 가 아님!
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots(a1[0], a1[1], ..)", a1) // 따라서, 값 증가하지 않음,
// foo(a ... T)의 a에 foo(val...) 으로 값을 넘겨주면, 포인터로 동작한다.
// 즉, call by reference 임
call_by_dots(a1[:]...)
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots(a1[:]...)", a1) // 따라서 값 증가.
// 따라서, 아래처럼 복합적으로 호출하는 것은 불가.
// call_by_dots(a1[0], a1[2], a1[3:]...) // compile error
// pointer 로 호출가능 하지만, 같은 크기 배열의 포인터만 인자값으로 허용
call_by_pointer(&a1)
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots(&a1)", a1)
call_by_slice(a1[:])
fmt.Printf("%-*s:%+v\n", 30, "call_by_slice(a1[:])", a1)
// call_by_slice(a1[0], a1[2], a1[3], a1[4]) // compile error
// call_by_slice2(a2[:]) // compile error
a2 := [3][2]int{
{11, 2},
{12, 2},
{13, 2},
}
fmt.Println("")
fmt.Printf("%-*s:%+v\n", 30, "original array 2", a2)
call_by_dots(a2[:]...)
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots(a2[:]...)", a2)
call_by_slice(a2[:])
fmt.Printf("%-*s:%+v\n", 30, "call_by_slice(a2[:])", a2)
// 포인터가 가르키는 배열의 크기가 다르므로 컴파일 에러
// call_by_pointer(&a2)
//fmt.Println(a2)
fmt.Println("")
fmt.Println("-------- slice ----------------------------------------------------")
s1 := make([][2]int, 5)
for i := 0; i < 5; i++ {
s1[i] = [2]int{11 + i, 3}
}
//s1 := [][2]int { // make([][2]int, 5)
// {11,3},
// {12,3},
// {13,3},
// {14,3},
// {15,3},
//}
fmt.Printf("%-*s:%+v\n", 30, "original slice 1", s1)
call_by_dots(s1[0], s1[1], s1[2], s1[3], s1[4])
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots(s1[0], s1[2],..)", s1)
call_by_dots(s1[:]...)
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots(s1[:]...)", s1)
// call_by_pointer(&s1) // compile error
// fmt.Println(a1)
s2 := [][2]int{
{1, 4},
{2, 4},
{3, 4},
}
fmt.Println("")
fmt.Printf("%-*s:%+v\n", 30, "original slice 2", s2)
call_by_dots(s2[:]...)
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots(s2[:]...)", s2)
s3 := [][]int{
{11,2,3},
{12,2,3},
}
fmt.Println("")
fmt.Printf("%-*s:%+v\n", 30, "original slice 3", s3)
call_by_slice2( s3 )
fmt.Printf("%-*s:%+v\n", 30, "call_by_slice2(s3)", s3)
call_by_dots2( s3... )
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots2(s3...)", s3)
call_by_dots2( s3[0], s3[1] ) // '값에의한호출'인데, []int 슬라이스이므로 참조'값'으로 호출된다.
// 결과적으로 '참조에의한호출'이 되는 셈.
fmt.Printf("%-*s:%+v\n", 30, "call_by_dots2(s3[0], s3[1])", s3)
return
}
실행 결과
$ go run call_func_with_arr.go
-------- array ----------------------------------------------------
original array 1 :[[11 1] [12 1] [13 1] [14 1] [15 1]]
call_by_dots(a1[0], a1[1], ..):[[11 1] [12 1] [13 1] [14 1] [15 1]]
call_by_dots(a1[:]...) :[[21 1] [22 1] [23 1] [24 1] [25 1]]
call_by_dots(&a1) :[[31 1] [32 1] [33 1] [34 1] [35 1]]
call_by_slice(a1[:]) :[[41 1] [42 1] [43 1] [44 1] [45 1]]
original array 2 :[[11 2] [12 2] [13 2]]
call_by_dots(a2[:]...) :[[21 2] [22 2] [23 2]]
call_by_slice(a2[:]) :[[31 2] [32 2] [33 2]]
-------- slice ----------------------------------------------------
original slice 1 :[[11 3] [12 3] [13 3] [14 3] [15 3]]
call_by_dots(s1[0], s1[2],..) :[[11 3] [12 3] [13 3] [14 3] [15 3]]
call_by_dots(s1[:]...) :[[21 3] [22 3] [23 3] [24 3] [25 3]]
original slice 2 :[[1 4] [2 4] [3 4]]
call_by_dots(s2[:]...) :[[11 4] [12 4] [13 4]]
original slice 3 :[[11 2 3] [12 2 3]]
call_by_slice2(s3) :[[21 2 3] [22 2 3]]
call_by_dots2(s3...) :[[31 2 3] [32 2 3]]
call_by_dots2(s3[0], s3[1]) :[[41 2 3] [42 2 3]]
$
반응형