[The Go Programming Language] 1장 튜토리얼 - 1.2 커맨드라인 인수

in #kr-dev6 years ago

modolee_logo
안녕하세요. 개발자 모도리입니다.
The Go Programming Language 라는 책으로 Go를 공부하고 있으며, 해당 책의 내용을 요약 정리해서 올리려고 합니다. 저는 번역본을 구매해서 공부하고 있습니다.

지난 게시물


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 루프를 돌면서 변수 argos.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]

Coin Marketplace

STEEM 0.15
TRX 0.16
JST 0.028
BTC 68750.43
ETH 2428.97
USDT 1.00
SBD 2.37