안녕하세요. 개발자 모도리입니다.
The Go Programming Language 라는 책으로 Go를 공부하고 있으며, 해당 책의 내용을 요약 정리해서 올리려고 합니다. 저는 번역본을 구매해서 공부하고 있습니다.
예제코드 라고 나오는 것들은 https://github.com/modolee/tgpl.git 에서 다운 받으실 수 있습니다.
var [이름] [타입] = [표현식][타입] 이나 = [표현식] 부분 중 하나는 생략 가능, 둘 다 생략은 불가능
[타입] 생략 : 초기화 표현식에 의해 타입이 결정[표현식] 생략 : 타입 별 제로 값 (숫자 : 0/ 불리언 : false / 문자열 : "" / 인터페이스, 참조 타입(슬라이스, 포인터, 맵, 채널, 함수) : nil)으로 초기화var s string
fmt.Println(s) // ""
var i, j, k int // int, int, int
var b, f, s = true, 2.3, "four" // bool, float64, string
var f, err = os.Open(name) // os.Open은 파일과 오류를 반환한다.짧은 변수 선언의 형태 : 이름 := 표현식
이름의 타입은 표현식의 타입에 의해 결정anim := gif.GIF{LoopCount: nframes}
freq := rand.Float64() * 3.0
t := 0.0
var 선언을 주로 사용하는 경우
i := 100 // an int
var boiling float64 = 100 // a float64
var names []string
var err error
var p Point
하나의 짧은 변수 선언으로 여러 변수를 선언하거나 초기화 할 수 있습니다.
i, j := 0, 1
=가 할당인 것에 반해 :=는 선언이라는 점을 염두에 둬야 합니다.
in, err := os.Open(infile)
// ...
out, err := os.Create(outfile)
f, err := os.Open(infile)
// ...
f, err := os.Create(outfile) // 컴파일 오류 : 새 변수 없음
포인터 값은 변수의 주소로, 값이 저장되어 있는 위치입니다.
포인터 표현식
var x int 를 선언&x - 타입 : *int | 명칭 : '정수 포인터' | 역할 : 정수 변수에 대한 포인터&x == p 라면 'p가 x를 가리킨다' 또는 'p에는 x의 주소가 있다'라고 말합니다.p가 가리키는 변수는 *p로 나타냅니다.*p 표현식은 변수의 값인 int를 생성하지만, *p가 변수 자체를 나타내므로 할당문의 왼쪽에 써서 변수를 갱신할 수도 있습니다.x := 1
p := &x // *int 타입 p는 x를 가리킴
fmt.Println(*p) // "1"
*p = 2 // x = 2와 같음
fmt.Println(x) // "2"
집합형 변수의 각 구성 요소인 구조체의 필드나 배열의 원소도 변수 이기 때문에 주소를 갖습니다.
변수를 나타내는 표현식에만 address-of 연산자(&)를 쓸 수 있습니다.
포인터 초기화, 비교
nil입니다.p가 변수를 가리키고 있다면 p != nil은 참입니다.nil일 경우에만 참입니다.var x, y int
fmt.Println(&x == &x, &x == &y, &x == nil) // "true false false"
함수는 지역 변수의 주소를 반환할 수 있습니다.
var p = f()
func f() *int {
v := 1
return &v
}
f를 호출해 생성 된 지역 변수 v는 호출이 반환된 후에도 존재하며, 포인터 p는 해당 값을 계속 참조할 수 있습니다.f를 호출 할 때마다 다른 값을 반환합니다.fmt.Println(f() == f()) // "false"포인터를 함수의 인자로 전달하면 함수에서 간접적으로 전달된 변수를 갱신할 수 있습니다.
func incr(p *int) int {
*p++ // p가 가라키는 값을 증가시키고, p는 변경하지 않습니다.
return *p
}
v := 1
incr(&v) // 부작용 : v는 2가 됩니다.
fmt.Println(incr(&v)) // "3" (v는 3)
echo4 - 포인터를 이용하는 flag 패키지 사용
package main
import (
"flag"
"fmt"
"strings"
)
var n = flag.Bool("n", false, "omit trailing newline")
var sep = flag.String("s", " ", "separator")
func main() {
flag.Parse()
fmt.Print(strings.Join(flag.Args(), *sep))
if !*n {
fmt.Println()
}
}
예제 코드 [ch2/echo4.go]
실행 결과
$ go build ch/echo4.go
$ ./echo4 a bc def
a bc def
$ ./echo4 -s / a bc def
a bc def $
$ ./echo4 -help
Usage of ./echo4:
-n omit trailing newline
-s string
separator (default " ")
p := new(int) // *int 타입 p는 이름 없는 int 변수를 가리킵니다.
fmt.Println(*p) // "0"
*p = 2 // 이름 없는 int를 2로 설정합니다.
fmt.Println(*p) // "2"
newInt1과 newInt2는 동일하게 동작합니다.func newInt1() *int {
return new(int)
}
func newInt2() *int {
var dummy int
return &dummy
}
p := new(int)
q := new(int)
fmt.Println(p == q) // "false"
func delta(old, new int) int { return new - old}
for t := 0.0; t < cycles*2*math.Pi; t += res {
x := math.Sin(t)
y := math.Sin(t*freq + phase)
img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
}
t : for 루프 시작 시 생성x, y : 루프의 각 반복 마다 새롭게 생성var global *int
func f() {
var x int
x = 1
global = &x
}
func g() {
y := new(int)
*y = 1
}
C와 같은 언어에서는 보통 정적으로 변수를 선언할 경우(go의 var) 스택에, 동적으로 선언할 경우(go의 new) 힙에 메모리를 할당합니다.