Go 언어에서 세 개의 점으로 이루어진 줄임표 연산자는 다양한 상황에서 사용됩니다. 이 글에서는 이 연산자의 세 가지 주요 용법을 실제 코드와 함께 설명하고, 자주 마주칠 수 있는 함정들을 짚어보겠습니다.
1. 배열 선언 시 길이 자동 결정
배열 리터럴에서 길이를 명시하는 자리에 줄임표를 사용하면, 초기화되는 요소의 개수에 따라 배열의 크기가 자동으로 결정됩니다.
package main
import "fmt"
func main() {
// 배열의 길이는 초기화 값 1, 2, 3에 의해 3으로 설정됨
arr := [...]int{1, 2, 3}
fmt.Printf("타입: %T, 길이: %d\n", arr, len(arr)) // [3]int, 3
}
위 예제에서 [...]int는 컴파일러가 요소 개수를 세어 [3]int 타입의 배열을 생성합니다.
2. 슬라이스 풀기 (Spread)
슬라이스 뒤에 줄임표를 붙이면 슬라이스의 요소들을 개별 인자로 풀어서 다른 함수나 연산에 전달할 수 있습니다. 주로 append 함수와 함께 사용됩니다.
package main
import "fmt"
func main() {
var numbers []int
data := []int{10, 20, 30}
// data... 는 data 슬라이스의 모든 요소를 개별 인자로 펼침
// 즉, append(numbers, 10, 20, 30) 과 동일
numbers = append(numbers, data...)
fmt.Println("결과:", numbers) // [10 20 30]
var bytes []byte
bytes = append(bytes, []byte("Go 언어")...)
fmt.Println("문자열:", string(bytes)) // Go 언어
}
이 방식은 가변 인자 함수를 호출할 때도 유용하게 사용됩니다.
3. 가변 인자 함수 선언
함수의 마지막 매개변수 타입 앞에 줄임표를 붙이면, 해당 함수는 개수가 정해지지 않은 인자를 받을 수 있습니다. 함수 내부에서는 이 인자들이 슬라이스 형태로 처리됩니다.
package main
import "fmt"
// sum 함수는 임의의 개수 정수를 받아 합계를 반환
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println("합계:", sum(1, 2, 3)) // 6
fmt.Println("합계:", sum(5, 10, 15, 20)) // 50
fmt.Println("합계:", sum()) // 0 (빈 호출 가능)
}
가변 인자 함수의 타입과 일반 슬라이스를 매개변수로 받는 함수의 타입은 서로 다르다는 점을 기억해야 합니다.
package main
import "fmt"
// 가변 인자 함수
func variadic(nums ...int) {
fmt.Println("variadic 내부:", nums)
}
// 슬라이스를 받는 일반 함수
func sliceParam(nums []int) {
fmt.Println("sliceParam 내부:", nums)
}
func main() {
data := []int{1, 2, 3}
variadic(data...) // 올바른 호출: 슬라이스를 풀어서 전달
// variadic(data) // 오류: []int 타입을 ...int에 직접 전달 불가
sliceParam(data) // 올바른 호출: 슬라이스 자체를 전달
// sliceParam(data...) // 오류: ...int 타입을 []int에 직접 전달 불가
}
주의할 점: interface{} 와의 상호작용
가변 인자로 ...interface{}를 사용할 때는 특히 주의가 필요합니다. interface{} 자체는 모든 타입을 담을 수 있지만, []interface{}는 []int나 []string과 완전히 다른 타입입니다.
오류가 발생하는 경우
package main
import "fmt"
func printArgs(args ...interface{}) {
fmt.Println(args)
}
func main() {
nums := []int{1, 2, 3}
// printArgs(nums...) // 오류: []int 타입을 ...interface{} 타입에 전달 불가
printArgs(nums) // 올바름: nums 자체가 하나의 interface{} 인자로 전달됨
}
위 예제에서 nums...를 직접 전달하면 타입 불일치 오류가 발생합니다. []int 타입의 슬라이스를 []interface{} 타입의 슬라이스로 자동 변환할 수 없기 때문입니다.
올바른 해결 방법
package main
import "fmt"
func printArgs(args ...interface{}) {
fmt.Println("args:", args)
}
func main() {
var mixed []interface{}
mixed = append(mixed, 1, "hello", 3.14)
// interface{} 슬라이스는 ...interface{}에 풀어서 전달 가능
printArgs(mixed...)
// 또는 개별 인자로 전달
printArgs(1, "hello", 3.14)
}
[]interface{} 타입의 슬라이스만이 ...interface{} 가변 인자에 풀어서 전달될 수 있습니다.
이러한 동작 방식을 이해하면 Go에서 줄임표 연산자를 더욱 안전하고 효과적으로 활용할 수 있습니다.