위키 사용법도 잘 모르고, GO도 처음인 방랑자가 혼자 끄적이기 위한 공간입니다.
다음 사이트를 정리 하면서, 참고를 하고 있어요...
1 Go 설치[ | ]
- 리눅스 민트 19.2 시나몬 배포판에 Go를 설치한다.
- Go 공식 웹사이트인 http://golang.org/dl 에서 Linux용 압축파일을 다운로드 받는다.
- /usr/local 에 압축을 푼다
Bash
Copy
$ tar -C /usr/local -xzf go1.14.2.linux-amd64.tar.gz
/usr/local/go 폴더 아래에 설치가 된다.
- "Go build error
- no non-test Go files in <dir>"
이런 에러가 나온다면...아마도 "apt-get install golang" 으로 낮은 버전을 설치 했을 것이다. 내 경운 그랬다....최신버전으로 설치를 하면 되더라..
- 환경변수 설정하기
Bash
Copy
$ export PATH=$PATH:/usr/local/go/bin
//go 컴파일러의 위치 /usr/local/go/bin를 PATH에 추가.
$ export GOPATH=$HOME/go
//작업 폴더의 위치를 알려 준다.
$ export GOBIN=$HOME/go/bin
//실행 파일이 저장될 위치.
$HOME/.profile 추가, 재로그인 하면 수정이 적용된다.
로그아웃 없이 .profile 적용하기, 둘중 하나 실행.
Bash
Copy
$ source .profile
$ . ./.profile
GOROOT="/usr/local/go" GOROOT는 자동으로 설정 된다.
- 작업 폴더 만들기
Bash
Copy
$ go get golang.org/x/tools/cmd/...
$HOME/go 아래에 bin, pkg, src 3개의 폴더가 생기고 이런 저런 파일 들이 만들어 진다. 이게 뭘하는 건지는 아직 모르겠다.
2 Go 편집기, Atom 설치[ | ]
- Atom 설치
http://atom.io 에서 "Download.deb"를 클릭해서 설치한다. 어렵지 않다 시키는 대로 하면 된다.
- Git 설치
https://git-scm.com/downloads 에서 "Downloads for Linux"를 클릭해서 설치 한다. 역시 어렵지 않았다, 뭘 하는건지를 몰라서 그렇지. Atom을 설치 할때 Git이 필요하다고 한다. Git에서 Atom을 만들었다고 하니까... 뭐 거창 한건줄,
Bash
Copy
$ apt-get install git
- 한줄 입력하면 되더라, 다른 버전 설치를 원하면 어쩌구 하는 설명이 몇줄 더 있고...
- Atom 필요한 패키지 설치
Atom 설치 후 Go에 필요한 패키지를 설치 한다. Help -> Welcome Guide, Install Package 에서 "go-plus" 검색 -> Install 클릭. 동일하게 "platformio-ide-terminal" 검색하여 설치한다.
3 Go 프로그래밍, 변수 와 상수[ | ]
- 변수
3.1 var 키워드 사용 하는 방법 var [변수명] [변수타입] = [초기값]
Go
Copy
var a int, a = 1
정수(int)형 변수를 선언하고, 나중에 초기화.
var f float32 = 11
실수(float)형 변수 선언과 초기화.
var a b c int = 1, 2, 3
여러개의 변수 선언 및 초기화.
" = " 빼먹고 개고생함...어이가 없네.
3.2 변수 타입을 생략 하고, 초기 값에 따라 변수 타입을 추론 하는 방법;
Go
Copy
var i = 1 var s = "Hi"
i 는 정수형이구나, s 는 문자형이겠구나. 이런 방법이 편할지는 모르겠지만, 나중에 귀찮아 질것 같다...
뭐든 기본이 중요하니까.. 별로 쓰고 싶진 않다.
3.3 := (Short Assignment Statement) 를 사용하는 방법 함수(func)내에서만 사용가능하고, 함수 밖에서는 var를 사용해야 한다. - 이건 불편하다 안쓸란다.
** 변수를 선언하면서 초기값을 지정하지 않으면, Zero Value를 기본적으로 할당한다.
- 상수
3.4 const [변수명] [변수타입] = [초기값] 키워드 const 를 사용 하는것 이외에는 변수 선언과 거의 비슷하다.
Go
Copy
const c int = 10
const s string = "Hi"
3.5 역시나 값을 보고 변수형을 추정하는 방식도 있다.
Go
Copy
const c = 10
const s = "Hi"
3.6 한번에 상수를 여러개 묶어서 만들 수 있다.
Go
Copy
const (
Visa = "Visa"
Master = "MasterCard"
Amex = "American Express"
)
3.7 상수의 값을 0부터 차례대로 할당 할때는 iota 를 사용한다.
Go
Copy
const (
Apple = iota // 0
Grape // 1
Orange // 2
)
## 당연한 거겠지만, GO에서 사용하는 키워드는 변수명에 사용할 수 없다. 25개가 있다는데 아직 뭘 하는건지 모르겠다..거의다...
4 Go 프로그래밍, 데이터 타입[ | ]
- Go 데이터 타입
- Go 프로그래밍 언어는 다음과 같은 기본적인 데이타 타입들을 갖고 있다.
데이터 타입 설명 문자열 string은 수정 될 수 없는 immutable 타입 부울린 bool 정수형 int int8 int16 int32 int64
unit unit8 unit16 unit32 unit64 unitptr실수형 float32 float64 복소수형 complex64 complex128 바이트 코드 byte: unit8 과 동일, 바이트 코드에 사용 유니 코드 rune: int32 와 동일, 바이트 코드에 사용
- 문자열
문자열 리터럴은 Back Quote(` `) 혹은 이중인용부호(" ")를 사용하여 표현할 수 있다.
Raw String Literal - Back Quote (` `)로 둘러 싸인 문자열 안에 있는 문자열은 별도로 해석되지 않고 Raw String 그대로의 값을 갖는다. 예를 들어, 문자열 안에 \n 이 있을 경우 이는 NewLine으로 해석되지 않는다. 또한, Back Quote은 복수 라인의 문자열을 표현할 때 자주 사용된다.
Interpreted String Literal - 이중인용부호(" ")로 둘러 싸인 문자열 복수 라인에 걸쳐 쓸 수 없으며, 인용부호 안의 Escape 문자열들은 특별한 의미로 해석된다. 예를 들어, 문자열 안에 \n 이 있을 경우 이는 NewLine으로 해석된다. 이중인용부호를 이용해 문자열을 여러 라인에 걸쳐 쓰기 위해서는 + 연산자를 이용해 결합하여 사용한다.
Go
Copy
interLiteral := "아리랑아리랑\n" +
"아리리요"
- 데이터 타입 변환
하나의 데이터 타입에서 다른 타입으로 변환을 하는것을 말한다. Go에서 타입간 변환은 명시적으로 지정해 주어야 한다. 암묵적 변환은 이뤄지지 않고, 런타임시 에러가 생긴다.
Go
Copy
var i int = 100
var u unit = unit(i) // 변수 = 변환될 타입(변환될 값)
5 Go 프로그래밍, Go 연산자[ | ]
연산자 설명은 마이 부족하다. 일단 이런게 있구나 하고 넘어가자 실재로 사용할때 한번씩 더 정리를 해서 추가 해야 할듯하다.
- 산술 연산자
사칙연산자(+, -, *, /, % (Modulus))와 증감연산자(++, --)
Go
Copy
c = (a + b) / 5
i++
- 관계연산자
서로의 크기를 비교하거나 동일함을 체크 한다.
Go
Copy
a == b
a != b
a <= b
- 논리연산자
AND, OR, NOT, XOR 을 표현하는데 사용된다.
Go
Copy
A && B
A || !(C && B)
1111 ^ 1010
- Bitwise 연산자
비트단위 연산을 위해 사용되는데, 바이너리 AND, OR, XOR와 바이너리 쉬프트 연산자가 있다.
Go
Copy
0011 & 0101
0011 ^ 0101
Bitwise operators 비트 연산자 요기에 아주 잘 설명되어 있다.
- 할당연산자
값을 할당하는 = 연산자 외에 사칙연산, 비트연산을 축약한 +=, &=, <<= 같은 연산자들도 있다.
Go
Copy
a = 100
a *= 10
a >>= 2
- 포인터연산자
C++와 같이 & 혹은 * 을 사용하여 해당 변수의 주소를 얻어내거나 이를 반대로 Dereference 할 때 사용한다.
Go
Copy
var k int = 10
var p = &k //k의 주소를 할당
println(*p) //p가 가리키는 주소에 있는 실제 내용을 출력
// 포인터연산자를 제공하지만 포인터 산술 즉 포인터에 더하고 빼는 기능은 제공하지 않는다.
포인터의 역참조 역참조 (Dereference) 에 대한 설명은 아무래도 C를 참고 하는게 좋을듯.
6 Go 프로그래밍, Go 조건문[ | ]
- if문
if 문은 해당 조건이 맞으면 { } 블럭안의 내용을 실행한다. 조건식을 괄호( )로 둘러 싸지 않아도 되며, 반드시 Boolean 식으로 표현되어야 한다. 그러나 반드시 조건 블럭 시작 브레이스({)를 if문과 같은 라인에 두어야 한다. 아니면 에러가 발생한다.
Go
Copy
if k == 1 { // if문과 { 는 같은 라인에
println("one")
}
else 문은 이전의 if 문들이 모두 거짓일 때 실행된다. else if 문은 if 조건문이 거짓일 때 다시 다른 if 조건식을 검사하는 데 사용된다. (복잡하긴 맞냐? 아니면 또 맞냐? 인거지.)
Go
Copy
if k == 1 {
println("one")
} else if k == 2 {
println("two")
} else {
println("other")
}
if 문에서 조건식을 사용하기 이전에 간단한 문장(Optional Statement)을 함께 실행할 수 있다. 정의된 변수 val는 if문 블럭 (혹은 if-else 블럭 scope) 안에서만 사용할 수 있다. 벗어나서 사용하면 에러발생
Go
Copy
if val := i * 2; val < max {
println(val)
}
- switch문
여러 값을 비교해야 하는 경우 혹은 다수의 조건식을 체크해야 하는 경우 switch 문을 사용한다. switch 문 뒤에 하나의 변수(혹은 Expression)를 지정하고 case 문에 해당 변수가 가질 수 있는 값들을 지정하여 값이 일치할 경우에 다른 문장 블럭들을 실행할 수 있다. # 복수의 값을 하나의 문장블럭으로 실행할 경우 콤마를 써서 나열 하면된다. # default: case 문에 일치하는 값이 없을 경우에 실행 된다.
Go
Copy
package main
func main() {
var name string
var catagory int = 1
switch catagory {
case 1:
name = "Paper Book"
case 2:
name = "eBook"
case 3, 4:
name = "Blog"
default :
name = "Other"
}
println(name)
//Expression을 사용한 경우
//switch x := category << 2; x - 1 {
//...
}
Loading
Go만의 특별한 용법들
switch 뒤에 expression이 없을 수 있음 다른 언어는 switch 키워드 뒤에 변수나 expression 반드시 두지만, Go는 이를 쓰지 않아도 된다.
이 경우 Go는 switch expression을 true로 생각하고 첫번째 case문으로 이동하여 검사한다.
//그냥 넘겨도 case문에서 조건을 지정할 수 있기에 가능하다.case문에 expression을 쓸 수 있음 다른 언어의 case문은 일반적으로 리터럴 값만을 갖지만,
Go는 case문에 복잡한 expression을 가질 수 있다
No default fall through 다른 언어의 case문은 break를 쓰지 않는 한 다음 case로 이동하지만,
Go는 다음 case로 가지 않는다
Type switch 다른 언어의 switch는 일반적으로 변수의 값을 기준으로 case로 분기하지만,
Go는 그 변수의 Type에 따라 case로 분기할 수 있다
Go의 switch 문에서 한가지 특징적인 용법은 switch 뒤에 조건변수 혹은 Expression을 적지 않는 용법이다. case 조건문들을 순서대로 검사하여 조건에 맞는 경우 해당 case 블럭을 실행하고 switch문을 빠져나온다. 복잡한 if...else if...else if... 문장을 단순화하는데 유용하다.
Go
Copy
func grade(score int) {
switch {
case score >= 90:
println("A")
case score >= 80:
println("B")
case score >= 70:
println("C")
case score >= 60:
println("D")
default:
println("No Hope")
}
}
Go의 또 다른 용법은 switch 변수의 타입을 검사하는 타입 switch가 있다. 아래 예제는 변수 v의 타입이 int 인지, bool, string 인지를 체크한 후 해당 case 블럭을 실행하는 예이다.
Go
Copy
switch v.(type) {
case int:
println("int")
case bool:
println("bool")
case string:
println("string")
default:
println("unknown")
}
# 이대로 실행을 하면 에러가 주루룩 나온다. func를 만들고 인자를 지정할때 interface{} 로 해야 제대로 실행이 된다. 이건 함수를 공부 할때 비로소 알 수 있을 것 같다. 함수의 인자 type이 바뀌는 함수를 만들때 필요한게 interface{} 인것 같다...짐작이다.
Go
Copy
func do( i interface{} ) {...}
Go는 case문 마지막에 break 문을 적든 break 문을 생략하든, 항상 break 하여 switch 문을 빠져나온다. Go 컴파일러가 자동으로 break 문을 각 case문 블럭 마지막에 추가하기 때문이다. case문을 빠저 나오지 않고 다음 case문으로 진행 하려면 fallthrough 문을 사용하면 된다.
Go
Copy
package main
import "fmt"
func main() {
check(2)
}
func check(val int) {
switch val {
case 1:
fmt.Println("1 이하")
fallthrough
case 2: //ckeck(2)로 호출, 따하서 case 2: 에서 default: 문까지 실행된다.
fmt.Println("2 이하")
fallthrough
case 3:
fmt.Println("3 이하")
fallthrough
default:
fmt.Println("default 도달")
}
}
Loading
7 Go 프로그래밍, Go 반목문[ | ]
- for 문
Go는 반복문에 for 하나 밖에 없다. "for 초기값; 조건식; 증감 { ... }" 의 형식을 따른다. 초기값, 조건식, 증감은 경우에 따라 생략이 가능하지만, 초기값; 조건식; 증감"을 둘러싸는 괄호 ( )를 생략하는데, 괄호를 쓰면 에러가 난다.
Go
Copy
func main() {
sum := 0
for i := 1; i <= 100; i++ { // 초기값; 조건식;증감 구분 세미콜론(;)
sum += i
}
println(sum)
}
- for 문 - 조건식만 쓰는 for 루프
Go에서 for 루프는 초기값과 증감식을 생략하고 조건식만을 사용할 수 있다. # 다른 언어의 while문과 비슷하다는데, 제일 많이 안쓸듯
Go
Copy
func main() {
n := 1
for n < 100 {
n *= 2
}
println(n)
}
- for 문 - 조건식만 쓰는 for 루프
무한루프를 만들려면 "초기값; 조건식; 증감" 모두를 생략하면 된다. Ctrl + C 로 빠져 나오면 된다.
Go
Copy
package main
func main() {
for {
println("Infinite loop")
}
}
- for range 문
"for 인덱스, 요소값 := range 컬렉션" 같이 for 루프를 구성 하고, range 키워드 다음의 컬렉션으로부터 하나씩 요소를 리턴해서 그 요소의 위치 인덱스와 값을 for 키워드 다음의 2개의 변수에 각각 할당한다. # 뭔소린가 하니 배열의 인덱스와 값을 for문 다음에 오는 2개의 변수에 순서대로 하나씩 끝날때 까지 가져 온다. 그런 말임.
Go
Copy
names := []string{"홍길동", "이순신", "강감찬"}
for index, name := range names { // index = 0, 1, 2 name = "홍길동", "이순신", "감감찬" 순서대로 값이 입력됨
println(index, name)
}
- break, continue, goto 문
break for 루프내에서 즉시 빠져나올 필요가 있는데, 이때 break 문을 사용한다. for문 이외에 select, switch문엣서 사용가능하다. "break 레이블" goto문 처럼 레이블을 사용할 수 도 있는데, for 문 바로 전에 레이블을 만들고 break 레이블, 형식으로 사용하는데 이 경우 for문의 다음으로 이동해서 진동하게 된다는데...이건 뭐 명시적이지도 이해 하기가 쉽지도 안는 불편한 기능이다. 있으나 마나.... continue for 루프의 중간에서 나머지 문장들을 실행하지 않고 for 루프 시작부분으로 바로 가려면 continue문을 사용한다. for 루프에서만 사용가능하다. goto 임의의 문장으로 이동하기 위해 goto 문을 사용할 수 있다. goto문은 for 루프와 관련없이 사용될 수 있다. # goto, break, continue 이게 쓸일이 있을지...쓴다 해도 나중에 어쩔라고...
Go
Copy
package main
func main() {
var a = 1
for a < 15 {
if a == 5 {
a += a
continue // for루프 시작으로
}
a++
if a > 10 {
break //루프 빠져나옴
}
}
if a == 11 {
goto END //goto 사용예
}
println(a)
END:
println("End")
}
Loading
8 Go 프로그래밍, Go 함수[ | ]
- 함수
함수는 여러 문장을 묶어서 실행하는 코드 블럭의 단위이다. Go에서 함수는 func 키워드를 사용하여 정의한다. func 뒤에 함수명을 적고 괄호 ( ) 안에 그 함수에 전달하는 파라미터들을 적게 된다. 함수 파라미터는 0개 이상 사용할 수 있는데, 각 파라미터는 파라미터명 뒤에 int, string 등의 파라미터 타입을 적어서 정의한다. 함수의 리턴 타입은 파라미터 괄호 ( ) 뒤에 적게 되는데, 이는 C와 같은 다른 언어에서 리턴 타입을 함수명 앞에 쓰는 것과 대조적이다. #함수의 파라미터의 타입도 변수 뒤에 둔다. 이게 변하다고 생각 한걸까? 함수는 패키지 안에 정의되며 호출되는 함수가 호출하는 함수의 반드시 앞에 위치해야 할 필요는 없다.
Go
Copy
package main
func main() {
msg := "Hello"
say(msg)
}
func say(msg string) { //함수가 정의되는 위치는 어디든 상관 없다.
println(msg)
}
Loading
- 정수형을 반환하는 함수
Go
Copy
func say(msg string) int {
println(msg)
return 1
}
- Pass By Reference
Go에서 파라미터를 전달하는 방식은 크게 Pass By Value와 Pass By Reference로 나뉜다. 1. Pass By Value msg의 값 "Hello" 문자열이 복사되어 함수 say()에 전달된다. (위의 예제 참조) 따라서 msg의 값이 say() 함수 내에서 변경 된다 하더라도 호출 함수 main() 에서 의 msg 변수는 변함이 없다. 2. Pass By Reference msg 변수의 주소를 전달하게 된다. msg 변수앞에 & 부호를 붙여 변수의 포인터(주소)를 전할하는 방식이다. 이경우 함수에서 msg의 값을 바꾸면, 변수의 값 자체가 바뀌게 된다. # 파라미터의 값을 바꾸고 싶으면 포인터를 이용한 Reference 방식을 바꾸기 싫다면 복사를 하는 Value 방식을 이용하면 된다.
Go
Copy
package main
func main() {
msg := "Hello"
say(&msg) //msg의 주소를 파라미터로 넘겨준다. &msg
println(msg) //변경된 메시지 출력
}
func say(msg *string) {
println(*msg)
*msg = "Changed" //메시지 변경
}
Loading
- Variadic Function (가변인자함수)
함수에 고정된 수의 파라미터들을 전달하지 않고 다양한 숫자의 파라미터를 전달하고자 할 때 가변 파라미터를 나타내는 ... (3개의 마침표)을 사용한다 즉 문자열 가변 파라미터를 나타내기 위해서 ...string 과 같이 표현한다. n개의 동일타입 파라미터를 전달할 수 있다. 이렇게 가변 파라미터를 받아들이는 함수를 Variadic Function (가변인자함수)라고 부른다.
Go
Copy
package main
func main() {
say("This", "is", "a", "book")
say("Hi")
}
func say(msg ...string) {
for _, s := range msg { //for 문의 range를 사용할때 인덱스를 생략 할때는 "for _ , " 이렇게 한다. 생략하면 말도 안되는 에러가 나더라.
println(s)
}
}
Loading
- 함수 리턴값
func 문의 (파라미터 괄호 다음) 마지막에 리턴값의 타입을 정의해 준다. 값을 리턴하기 위해 함수내에서 return 키워드를 사용한다. Go 프로그래밍 언어에서 함수는 1. 리턴값이 없을 수도, 지금가지 연습했던 함수들이 리턴값이 없는 함수다. 2. 리턴값이 하나 일 수도,
Go
Copy
package main
func main() {
total := sum(1, 7, 3, 5, 9)
println(total) //total 함수가 리턴하는 하나의 값을 출력한다.
}
func sum(nums ...int) int { //리턴값의 타입을 저의: 정수형 하나를 리턴 한다.
s := 0
for _, n := range nums {
s += n
}
return s //정수형 값을 리턴한다.
}
Loading
3. 또는 리턴값이 복수 개일 수도 있다. Go에서 복수 개의 값을 리턴하기 위해서는 해당 리턴 타입들을 괄호 ( ) 안에 적어 준다. 예를 들어, 처음 리턴값이 int이고 두번째 리턴값이 string 인 경우 (int, string) 과 같이 적어 준다.
Go
Copy
package main
func main() {
count, total := sum(1, 7, 3, 5, 9)
println(count, total)
}
func sum(nums ...int) (int, int){ // 리턴값은 (int, int) 2개가 될거라고 선언하는 거다.
s := 0 // 합계
count := 0 // 요소 갯수
for _, n := range nums {
s += n
count++
}
return count, s
}
Loading
4. Named Return Parameter 리턴값에 이름을 지정해 준다. 이렇게 하면, 리턴되는 값들이 여러 개일 때, 코드 가독성을 높이는 장점이 있다. func 라인의 마지막 리턴타입 정의 부분을 보면, (int, int) 가 아니라 (count int, total int) 처럼 정의되어 있음을 볼 수 있다. 즉, 리턴 파라미터명과 그 타입을 함께 정의한 것이다. 그리고 함수 내에서는 이 count, total에 결과값을 직접 할당하고 있음을 볼 수 있다.
Go
Copy
func sum(nums ...int) (count int, total int) {
for _, n := range nums {
total += n
}
count = len(nums)
return // return count, total 지정을 해줘도 되더라, 리턴값의 이름을 생략해도 된다, 그래도 return 자체를 생략해서는 안된다.
}
9 Go 프로그래밍, Go 익명함수[ | ]
- 익명함수
- 함수명을 갖지 않는 함수를 익명함수(Anonymous Function)이라 부른다.
- 일반적으로 익명함수는 그 함수 전체를 변수에 할당하거나 다른 함수의 파라미터에 직접 정의되어 사용되곤 한다.
- func 바로 뒤에 함수명을 생략 하는점을 제외하고 함수의 정의 내용을 동일하다.
- 일단 익명함수가 변수에 할당된 이후에는 변수명이 함수명과 같이 취급되며 "변수명(파라미터들)" 형식으로 함수를 호출할 수 있다.
Go
Copy
package main
func main() {
sum := func(n ...int) int { //익명함수 정의
s := 0
for _, i := range n {
s += i
}
return s
}
result := sum(1, 2, 3, 4, 5) //익명함수 호출
println(result)
}
Loading
- 일급함수
- 함수를 변수와 동일 하게 취급한다 이때 사용된 함수를 일급함수라 고 부른다.
- 변수 처럼 다른 함수에 매개변수로 줄 수도 있고 함수를 반환할 수도 있다, 그냥 변수 처럼 사용할 수 있다.
- 항상 느끼는 거지만, 이걸 어따가 써묵을지 오늘의 나는 이해를 못하고 있다.
Go
Copy
package main
func main() {
//변수 add 에 익명함수 할당
add := func(i int, j int) int {
return i + j
}
// add 함수 전달
r1 := calc(add, 10, 20)
println(r1)
// 직접 첫번째 파라미터에 익명함수를 정의함
r2 := calc(func(x int, y int) int { return x - y }, 10, 20)
println(r2)
}
func calc(f func(int, int) int, a int, b int) int {
result := f(a, b)
return result
}
Loading
- type문을 사용한 함수 원형 정의
- type 문은 구조체(struct), 인터페이스 등 Custom Type(혹은 User Defined Type)을 정의하기 위해 사용된다.
- 함수 원형을 정의하는데 사용될 수 있다. 즉, 위 예제에서 func(x int, y int) int 함수 원형이 코드 상에 계속 반복됨을 볼 수 있는데,
- 이 경우 type 문을 정의함으로써 해당 함수의 원형을 간단히 표현할 수 있다.
Go
Copy
// 원형 정의
type calculator func(int, int) int
// calculator 원형 사용
func calc(f calculator, a int, b int) int {
result := f(a, b)
return result
}
10 Go 프로그래밍, Go 클로저[ | ]
- 클로저 (Closure)
- 내부함수는 외부함수의 지역변수에 접근 할 수 있는데 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근 할 수 있다.
- 이러한 메커니즘을 클로저라고 한다. 와 뭔소린지 오늘의 내가 이해한건 여기까지.
- 1. 내부함수에서 외부함수에서 선언된 변수를 사용한다면 그 내부함수는 클로저이다.
- 2. 내부함수에서 사용된 외부함수의 변수는 그 값이 유지된다.
Go
Copy
package main
func nextValue() func() int {
i := 0
return func() int { //i를 1씩 증가 시키는 익명함수를 리턴한다.
i++
return i
}
}
func main() {
// nextValue()가 호출될때만 i의 값은 0으로 초기화,
// next()는 린턴된 익명함수의 레퍼런스는 유지가 되니까, i의 값이 유지(증가)되는게 아닐까?
next := nextValue()
println(next()) // 1
println(next()) // 2
println(next()) // 3
anotherNext := nextValue()
println(anotherNext()) // 1 다시 시작
println(anotherNext()) // 2
}
Loading
11 Go 프로그래밍, Go 배열[ | ]
- 1. 배열(Array)
- 배열은 연속적인 메모리 공간에 동일한 타입의 데이타를 순서적으로 저장하는 자료구조이다.
- Go에서 배열의 첫번째 요소는 0번, 그 다음은 1번, 2번 등으로 인덱스를 매긴다. (Zero based array)
- 배열의 선언은 "var 변수명 [배열크기] 데이타타입" 과 같이 하는데, 배열크기를 데이타타입 앞에 써 주는 것이 C, Java 같은 다른 언어들과 다르다.
- Go에서 배열의 배열크기는 Type을 구성하는 한 요소이다. 즉, [3]int와 [5]int는 서로 다른 타입으로 인식된다.
- 배열이 선언된 후에 각 배열의 요소를 인덱스를 사용하여 읽거나 쓸 수 있다.
Go
Copy
package main
func main() {
var a [3]int //정수형 3개 요소를 갖는 배열 a 선언
a[0] = 1
a[1] = 2
a[2] = 3
println(a[1]) // 2 출력
}
Loading
- 2. 배열의 초기화
- 배열을 정의할 때, 초기값을 설정할 수도 있다. 초기값은 "[배열크기] 데이타타입" 뒤에 { } 괄호를 두고 초기값을 순서대로 적으면 된다.
- 초기화 과정에서 [...] 를 사용하여 배열크기를 생략하면 자동으로 초기화 요소 숫자만큼 배열크기가 정해진다.
Go
Copy
var a1 = [3]int{1, 2, 3}
var a3 = [...]int{1, 2, 3} //배열크기 자동으로
- 3. 다배열 배열(다차원 배열)
- Go 언어는 다차원 배열을 지원한다. 다차원 배열은 배열크기 부분을 복수 개로 설정하여 선언한다.
- 예를 들어, 3 x 4 x 5 차원 정수 배열을 만들려면, 다음과 같이 배열을 정의한다.
- 다차원 배열의 사용은 일차원 배열과 유사하게 각 차원별 배열인덱스를 지정하여 사용한다.
Go
Copy
var multiArray [3][4][5]int // 정의
multiArray[0][1][2] = 10 // 사용
- 4. 다차원 배열의 초기화
- 다차원 배열의 초기화는 단차원 배열의 초기화와 비슷하다. 다만, 다 차원이므로 배열 초기값 안에 다시 배열값을 넣는 형태를 띤다.
- 다차원 배열은 배열의 배열 이니 배열의 구분은 콤마(,)로 전체 배열은 중괄호 {} 로 한번더 묶어 주면된다.
Go
Copy
package main
func main() {
var a = [2][3]int{ // 배열 천제를 중괄호 ( {} )로 한번더 싸준다
{1, 2, 3}, // 배열간 구분은 콤마( ' )
{4, 5, 6}, // 콤마를 생략 하면 에러 발생
}
println(a[1][2])
}
Loading
12 Go 프로그래밍, Go 슬라이스(Slice)[ | ]
- 1. 슬라이스(Slice)
- 슬라이스는 배열과 달리 고정된 크기를 미리 지정하지 않을 수 있고, 차후 그 크기를 동적으로 변경할 수도 있고, 또한 부분 배열을 발췌할 수도 있다.
- 선언은 배열을 선언하듯이 "var v []T" 처럼 하는데 배열과 달리 크기는 지정하지 않는다.
- GoCopy
package main import "fmt" func main() { var a []int //슬라이스 변수 선언 a = []int{1, 2, 3} //슬라이스에 리터럴값 지정 a[1] = 10 fmt.Println(a) // [1, 10, 3]출력 }
Loading - make() 함수로 슬라이스를 생성하면, 개발자가 슬라이스의 길이(Length)와 용량(Capacity)을 임의로 지정할 수 있는 장점이 있다.
- make() 함수의 첫번째 파라미터에 생성할 슬라이스 타입을 지정하고,
- 두번째는 Length (슬라이스의 길이), 그리고
- 세번째는 Capacity (내부 배열의 최대 길이)를 지정하면, 모든 요소가 Zero value인 슬라이스를 만들게 된다.
- 세번째 Capacity 파라미터를 생략하면 Capacity는 Length와 같은 값을 갖는다.
- GoCopy
package main func main() { s := make([]int, 5, 10) println(len(s), cap(s)) // len 5, cap 10 }
Loading - 슬라이스에 별도의 길이와 용량을 지정하지 않으면, 기본적으로 길이와 용량이 0 인 슬라이스를 만드는데,
- 이를 Nil Slice 라 하고, nil 과 비교하면 참을 리턴한다.
- GoCopy
package main func main() { var s []int if s == nil { println("Nil Slice") } println(len(s), cap(s)) // len 0, cap 0 }
Loading - 2. 부분 슬라이스(Sub-slice)
- 슬라이스에서 일부를 발췌하여 부분 슬라이스를 만들 수 있다.
- "슬라이스[처음인덱스:마지막인덱스+1]" 형식으로 만든다.
- 마지막 인덱스+1은 처음 인덱스에서 몇개를 가져 올건가(마지막 인텍스 = 처음인텍스 + 가저올갯수)로 이해를 하면 쉽다.
- GoCopy
package main import "fmt" func main() { s := []int{0, 1, 2, 3, 4, 5} // 2번째 인덱스부터 3개를 슬라이스 // 부분 슬라이스를 해도 원래의 값은 변하지 않는다 // // 변수의 이름이 같아 덮어 쓸줄 알았는데 // 슬라이스와 부분 슬라이스를 컴파일러가 구분을 하고 값을 유지 하는것 같다. 똑쪽하다 s = s[2:5] fmt.Println(s) //2,3,4 출력 }
Loading
13 같이 보기[ | ]
편집자 I972 Jmnote Jmnote bot
로그인하시면 댓글을 쓸 수 있습니다.