
안녕하세요. 개발자 모도리입니다.
**[The Go Programming Language](https://www.gopl.io/)** 라는 책으로 Go를 공부하고 있으며, 해당 책의 내용을 요약 정리해서 올리려고 합니다. 저는 [번역본](http://www.aladin.co.kr/shop/wproduct.aspx?ItemId=76703559)을 구매해서 공부하고 있습니다.
### 지난 게시물
* [[Go] Mac에서 Atom으로 Go 개발 환경 구축하기](https://steemit.com/kr-dev/@modolee/go-mac-atom-go)
* [[The Go Programming Language] 1장 튜토리얼 - 1.1 Hello, World](https://steemit.com/kr-dev/@modolee/the-go-programming-language-1-hello-world)
---
# 1장 튜토리얼
## 1.2 커맨드라인 인수(Arguments)
* 프로그램이 데이터를 입력 방법 중 하나는 커맨드라인의 인수로 데이터를 받는 방법입니다.
* Go에서는 os 패키지의 Args 변수(os.Args)를 통해서 커맨드라인 인수에 접근할 수 있습니다.
* `os.Args`는 문자열의 슬라이스인데, 기본 개념은 문자열 배열과 비슷하다고 생각하시면 됩니다.
> **슬라이스 관련 명령**
* `s[i]` : s의 **i** 번째 원소
* `s[m:n]` : s의 **m** 번째 원소부터 **n-1** 번째 원소까지의 집합
* `s[m:]` : s의 **m**번째 원소부터 마지막 원소까지의 집합
* `s[:n]` : s의 첫번째 원소부터 **n**번째 원소까지의 집합
* `len(s)` : s가 포함하는 **원소의 개수**
* `os.Args`의 첫번째 요소인 `os.Args[0]`는 명령 자체의 이름입니다.
* 그 외의 요소들은 명령어 이후의 커맨드라인에 인수로 들어온 값들입니다.
### echo 명령 구현 1
* 커맨드라인의 인수를 한 줄로 출력하는 유닉스 echo 명령의 구현
```
// echo1은 커맨드라인 인수를 출력합니다.
package main
import (
"fmt"
"os"
)
func main() {
var s, sep string
for i := 1; i < len(os.Args); i++ {
s += sep + os.Args[i]
sep = " "
}
fmt.Println(s)
}
```
*예제코드 [ch1/echo1.go]*
> **실행결과**
> $ go run ch1/echo1.go hi hello bye seeya
> hi hello bye seeya
* **주석 (line 1)**
* 주석은 `//`로 시작합니다.
* main 패키지의 주석은 전체 프로그램을 설명하는 하나 이상의 완전한 문장입니다.
* **import (line 4 ~ 7)**
* 두 개의 패키지를 단독 import 선언들 대신 괄호로 묶인 선언으로 import합니다. 아래과 동일한 표현입니다.
```
import "fmt"
import "os"
```
* 임포트의 순서는 중요하지 않는데, 그 이유는 gofmt 도구가 패키지명을 알파벳순으로 정렬해 주기 때문입니다. 아래과 같이 코드를 작성해도 저장할 때 자동으로 알파벳으로 정렬됩니다.
```
import (
"os"
"fmt"
)
```
* **변수 선언 (line 10 ~ 11)**
* var 선언은 `s, sep` 두 변수를 문자열 타입으로 선언합니다.
* 변수는 선언 중에 초기화 할 수 있습니다.
* 명시적으로 초기화되지 않은 경우에는 암시적으로 해당 타입의 zero value로 초기화 됩니다. (숫자형 변수의 zero value는 `0`, 문자형 변수의 zero value는 `""` )
* 따라서 *예제코드 [ch1/echo1.go]*에서는 `s, sep`는 모두 빈 문자열(`""`)으로 초기화 됩니다.
* 루프 인덱스로 사용되는 변수 `i` 는 `:=` 기호로 선언되어 있는데, 이것은 하나 이상의 변수를 선언하고 초기화 값을 할당하는 짧은 변수 선언 방법입니다.
* **증가 구문 (line 11)**
* `i++` 는 `i`에 1을 더하는 구문입니다. `i += 1`, `i = i + 1` 과 같습니다.
* 반대로 `i--`는 1을 빼는 구문입니다.
* 대부분의 C 계열의 언어와 달리 표현식(expressions)이 아닌 문장(statements)이기 때문에 `j = i++`는 허용되지 않으며, 후치 연산자(postfix)만 허용하기 때문에 `++i`도 허용되지 않습니다.
* **반복문 (line 11)**
* Go의 유일한 루프는 for 문입니다.
* 3가지 형태로 사용할 수 있습니다.
```
// 가장 기본적인 for 루프
// 초기화; 조건; 후처리 를 괄호로 묶지 않습니다.
for 초기화; 조건; 후처리 {
// 0개 이상의 구문
}
// while 루프 대체
for 조건 {
// . . .
}
// 무한 루프
for {
// . . .
}
```
* **연산자 (line 12)**
* 숫자에 일반적인 산술 연산자와 논리 연산자를 제공합니다.
* 문자열의 경우 `+` 연산자는 두 값을 결합합니다.
```
sep + os.Args[i] // 문자열 sep와 os.Args[i]의 결합을 나타냅니다.
s += sep + os.Args[i] // s의 이전 값에 sep와 os.Args[i]를 연결하고, 이를 다시 s에 할당합니다.
s = s + sep + os.Args[i] // 위와 동일합니다.
```
### echo 명령 구현 2
* echo1과 동일하나 for 루프 범위를 슬라이스로 표현
```
// echo2은 커맨드라인 인수를 출력합니다.
package main
import (
"fmt"
"os"
)
func main() {
var s, sep string
for _, arg := range os.Args[1:] {
s += sep + arg
sep = " "
}
fmt.Println(s)
}
```
*예제코드 [ch1/echo2.go]*
* **for 루프 범위 설정 (line 11)**
* `range`는 루프의 각 반복에서 값의 쌍(**index, index에 있는 원소의 값**) 을 생성합니다.
* for 루프를 돌면서 변수 `arg`에 `os.Args`의 index 1의 원소 값 부터 마지막 원소 값까지 할당합니다.
* *예제코드 [ch1/echo2.go]*에서는 index를 사용하지 않지만, range 문의 문법상 index를 처리해야 합니다.
* 그 방법으로 `_`(밑줄)로 표기되는 빈 식별자를 사용하면 됩니다.
> **다양한 변수 선언 및 초기화 방법**
> `s := ""` // 가장 간결하지만, 패키지 수준 변수가 아닌 함수 안에서만 사용할 수 있습니다.
> `var s string` // 문자열의 기본 초기 값에 의존하는 형식입니다.
> `var s = ""` // 여러 변수를 선언하는 경우 외에는 거의 사용 되지 않습니다.
> `var s string = ""` // 변수의 타입과 초기 값의 타입이 다른 경우에 사용합니다.
> 주로 앞의 두 가지 방법 중 하나를 사용합니다.
### echo 명령 구현 3
* echo1, 2는 루프의 반복마다 문자열 `s`는 완전히 새로운 값을 갖습니다.
* `+=`문은 기존 문자열, 공백 문자, 다음 인자를 경합한 새로운 문자열을 생성하고 `s`에 할당합니다.
* `s`의 이전 값은 더 이상 사용되지 않으므로 이후 가비지 컬렉션 될 것입니다.
* 관련 데이터의 양이 큰 경우 이 방식은 비용이 많이 들기 때문에, strings 패키지의 `Join`함수를 사용해서 echo3를 구현해 보겠습니다.
```
package main
import (
"fmt"
"os"
"strings"
)
func main() {
fmt.Println(strings.Join(os.Args[1:], " "))
}
```
*예제코드 [ch1/echo3.go]*
### 디버깅 용
* 형식에 상관 없이 값만 보려 할 때는 Println이 알아서 결과를 포매팅하게 할 수 있습니다.
```
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.Args[1:])
}
```
*예제코드 [ch1/echo_debug.go]*
> **실행결과**
> $ go run ch1/echo_debug.go hi hello bye seeya
> [hi hello bye seeya]