220516

jo1132·2022년 5월 16일
0
post-thumbnail

Go Language

Intro

  • 참조 : 주소값에 의한 참조(주소값을 보냄, Python), 값에 의한 참조
  • 포인터 : C에서 보던 포인터 이다.
  • 메소드, 인터페이스, 임베딩
  • 에러(Error) == 패닉(Panic)
  • 동시성(co currency) : 멀티 프로세싱, go루틴 채널
  • 코드를 누구나 비슷한 코딩 스타일을 가지게하는 규칙성이 있다.
  • 트랜젝션 : 여러 작업을 한 단위로 보는것. (원자성, 원자적 연산, 쪼개면 작업의 의미를 잃는다.)
  • 표준 라이브러리(Standard lib)
  • JSON
  • 컨텍스트
  • 테스트 작성 : 테스트 주도 개발.
  • 리플렉션 : 런타입에 동적 (실행중에 타입을 컨트롤 한다.)
  • 언세이프
  • CGO : 성능이아닌 통합
  • 제네릭 : 객체지향에서 주로 사용, 반복코드를 줄이고, 타입 세이프를 증가. 알고리즘을 추상화(공통되는것을 꺼내옴), 일반화.
  • 고는 컴파일언어이다. (속도가 빠르다. 개발기간이 길다.)
    • 코드가 다 완성되어야 컴파일이 가능하다.
    • 인터프리터언어에 비해 에러 수정이 조금 어렵다.

Chap 1

scale up VS scale out

scale up

  • 컴퓨터를 구성하는 하드웨어의 성능을 높이는것.
  • 한계 비용의 법칙 : 1Gb -> 2Gb 만큼 성능을 높히는데 1만원이 들 때, 10-> 11Gb 만큼 성능을 높히는데 10만원이 들게된다.

scale out

  • 컴퓨터를 추가해서 성능을 높이는것.
  • 컴퓨터를 추가하기 때문에 컴퓨터간 연결이 필요함
  • 이 과정을 통해 컴퓨터를 개념 단위로 묶은 것을 클러스터라 한다.

1. GO Install

  • go.dev 페이지로 이동
  • windows버전으로 설치
  • GOPATH 환경변수가 자동으로 설치된 것을 볼 수 있다.

1.2 GO 작업 공간

GOPATH 환경 변수

작업 공간의 기본 디렉토리

  • $HOME/go : $로 시작하여 HOME위치에 /go라는 디렉토리가 있다.
  • 쉘이란?
    • 리눅스에서 쉘은 명령어와 프로그램을 실행할 때 사용하는 인터페이스이다.
    • 함수에서 인터페이스는 함수의헤더이다.
      - 인자는 뭔지, 반환값은 뭔지 등
  • 사용자의 기본 경로이다.
    • USERPROFILE = \Users\r2com 으로 되어있다.
    • 위 경로는 %USERPROFILE%로 오른쪽 경로를 불러올 수 있다.
  • %GOPATH%\bin
  • %GOPATH%\src
  • setx해서 환경변수를 변경할 수 있다.

1.3 GO 명령어

  • go커맨드 라인 프로그램의 명령어이다.
  • go run go 파일..., | go 패키지
    • 작은 프로그램 테스트, 개발할 때
    • Go를 스크립트 언어처럼 사용 시
  • go build go 파일...| go 패키지 : 실행파일을 생성 (실행파일 -> 배포본)

명령어 사용해보기

  • 명령 프롬프트에서 notepad hello.go 해서 노트패드 생성
package main
import "fmt"
func main(){
	fmt.Println("Hey World!")
}

  • go run hello.go 해서 명령어 실행
  • go build hello.go를 실행해보았다.
  • hello.exe가 생성된 것을 볼 수 있으며 실행파일이라 용량이 많이 들어난 것을 볼 수 있다.
  • 또, hello.exe로 실행하면 출력이 제대로 나온다.
  • go build -o huyWorld.exe hello.go : -o 옵션으로 실행파일의 이름을 바꿔줄 수 있다. 이름을 바꿔실행파일을 생성하고 실행해본다.
  • C언어처럼 import 와 main이 필요하다.
    • 만약 메인이 아니라 서브 함수? 같이 만드려면 메인이 아니라 스스로의 함수이름?으로 만들면 될 것이다.

서드파티 Go 도구 설치

  • go는 다른 언어와 달리 자신의 코드 저장소를 공유하여 패키지를 직접 다운받고 설치 가능하다.
  • HTTP서버의 부하 테스트를 위한 hey라는 Go도구를 설치해본다.
  • 설치와 동시에 go라는 폴더가 생겼다.
  • 총 2.6초가량 걸렸다.
  • 실행파일만 배포한다면 상업적 목적으로든지 실행만 할 수 있다. go install을 사용할 수 없게 해도 된다.
  • 그러나 go install로 설치할 수 있도록 배포하면 다른 개발자들이 사용하고, 개발할 수 있게 배포할 수 있다.

코드 포맷팅

  • 효율적인 코드 작성을 위함


    go fmt
  • 들여쓰기 공백 수정
  • 구조체 항목 정렬
  • 연산자 주변 적절한 공백 사용 체크


    goimports
  • import 문 정리
    • 알파벳 순 정렬
    • 사용되지 않은 import 삭제
    • import 추측(추론): 100% 정확하지 않음
  • enhanced go fmt
  • go install 명령으로 설치 필요 (p.28 참조)


    세미콜론 삽입 규칙
  • go fmt는 이 규칙에 의해 잘못 삽입된 중괄호({})는 수정 못함
  • Go 컴파일러가 자동으로 문장 끝에 세미콜론을 붙여줌
  • 규칙
    • 식별자
    • 기본 리터럴
    • 다음 토큰 중 하나: break, continue, fallthrough, return, ++, '__', }, )
     package main
    import "fmt"
    func main()		// 세미콜론이 여기에 자동으로 붙어버려서 에러가 나게된다.
    {				// 에러가 없으러면, 괄호를 내리지 않아야 한다.
        fmt.Println("Hey World!")
    }

1.4 린팅, 베팅

Effective Go

type T struct {
    name string // name of the object
    value int // its value
}
  • python과 같은 언어에서는 위와같이 작성하는 규칙을 따른다.
type T struct {
    name    string // name of the object
    value   int    // its value
}
  • 그러나 Go에서는 tab을 사용하여 변수명까지 선을 맞추는 규칙을 사용한다.
  • 이렇게 선을 맞추는것을 린팅이라고 한다.

Go 위키의 코드 리뷰 규칙


linter

  • 1978년 시작
  • 코드가 스타일 가이드를 잘 지켰는지 확인
    • 알맞은 변수 이름을 지정
  • 100% 정확하지는 않다.
  • golint ./..... 해서 사용할 수 있다.

vetting

  • 추가적인 코드 스타일과 잠재적인 버그를 찾아주는 서드 파티 도구
  • go vet ./... 해서 사용한다.

golangci-lint

  • 위 lint와 vet를 동시에 작업한다.
  • golang-lint run 해서 사용한다.
  • 프로젝트 루트 디렉토리에 .golangci.yml파일을 만들어 활성화하고자 하는 린터와 분석할 파일을 설정할 수 있다.
  • 그러나 팀 프로젝트시 팀원의 동의가 진행되는 것이 좋다.

1.5 개발도구 소개

비주얼 스튜디오

Go 개발을 위한 VS Code 구성

  • VScode에서 go를 설치하여 사용할 수 있다.

GoLand

  • 젯브레인스(Jetbrains)에서 만든 Go 전용 IDE이다.
  • 파이참, 인텔리제이, 안드로이드 스튜디오와 비슷하게 생겼다.
  • 상용버전만 존재한다.

Go 플레이 그라운드

1.6 빌드 툴 Makefiles

  • make 프로그램 필요
  • make lint : make 파일을 아래 동작을을 한번에 해준다.
.DEFAULT_GOAL := build
//
fmt : 
	go fmt ./...
  //  
lint : fmt
	golint ./...
//
vet : fmt
	go vme ./...
//
build : vet
	go build hello.go
//
make == make build
  • 개발 환경을 빌드할 때, 한줄한줄 따로 입력하지 않게, 하나의 txt파일로 만들어 한번에 개발환경을 설치하는 방법이다.
  • 개발자가 빌드를 할대에 어떤 단계도 빠드리지 않고 진행되도록 한다.
  • Makefiles는 매우 까다롭다.
    - 타깃이 수행해야 하는 단계는 무조건 탭,
    - 윈도우에서는 기본으로 지원되지은 않지만, Chocolatey와 같은 윈도우 패키지 관리자를 먼저 설치하고, 그걸로 make를 설치하여 쉽게 설치할 수 있다.

1.7 항상 최신으로 유지

  • go get golang.org/dl/go.1.15.6
  • 위 명령어로 go 1.15.6버전을 다운로드 받을 수 있다.

2. 기본 데이터 타입과 선언

2.1 내장타입

  • bool type : bool
  • interger numeric : int8, uint8, int16, uint16, int32, uint32,int64, uint64, int, uint, intptr
  • float : float32, float64
  • complex numeric : complex64, complex128
  • string : string
  • byte는 uint8의 별칭이다. 즉, byte와 uint8는 같다.
  • rune도 마찬가지로 int32의 별칭이다. 즉, rune은 int32와 같다.

2.1.1 제로값

  • 선언되었지만 값이 할당되지 않은 모든 변수에 기본값인 제로 값zero value를 할당한다.

2.1.2 리터럴

  • Go에서 리터럴은 숫자, 문자 혹은 문자열을 쓰는 것을 나타낸다. (값 자체)
  • 정수 리터럴
    • 10진수, 8진수, 16진수, 2진수 => 접두사 이용 (없음, 0o, 0x, 0b)
    • 밑줄(underscore) : 정수 리터럴 사이에 밑줄은 컴퓨터가 무시한다. 즉, 가독성을 좋게 하기위해 사용할 수 있고, 계산에 영향을 미치지 않는다.
  • 부동 소수점 리터럴
    • 점(.)
    • e(E) 지수 표현
    • 밑줄 가능하다.
  • rune 리터럴
    • 작은 따옴표
    • 단일 유니코드 문자, 8bit 8진 숫자, 8bit 16진수 숫자, 16bit 16진수 숫자, 32비트 유니코드
    • 이스케이프 시퀀스: '\n', '\t',...
  • 문자 리터럴
      1. 해석된 문자열 리터럴 : 큰 따옴표 사용
      • 이스케이프 룬이 처리가 된다.
      1. raw 문자열 : 역따옴표(Back tick)사용
  • 다른 타입으로 선언된 두 정수는 연산 불가능하다.
    • int 8과 int 16을 더하려고 하면 에러가 표시된다.
    • 리터럴 자체에는 데이터 타입이 없기 때문이다.
  • Go 언어는 실용적 언어 => 리터럴에는 타입이 정해져 있지 않다.

2.1.3 불리안

  • true, false의 값을 갖는다.

2.1.4 숫자 타입

  • 곱셈연산에서 CPU는 ADD연산을 곱셈만큼 한다.
  • 만약 뺄셈은 어떻게 하는가?
    • 보수 (complement)
      • n진법 : n의 보수 => n-1의 보수 + 1,
        n-1의 보수 => 각 자리의 수를 n-1에서 뺀 것.
      1234 - 2294 => 1234 + 7705 (+1) = 8940 (보수)=> 1060
  • 정수 타입
    • 특수합 경우 아니면 int 사용
    • int가 기본 타입
  • 특수 정수 타입들
    • byte: uint8 보다 선호
    • int: 플랫폼에 따라서 int32, int64 (int32도 많이 포함하기 때문에, 거의32를 사용)
    • rune도 int32지만 용도가 다르다.
    • uintptr: 포인터
  • 정수 연산자
    • 정수 연산자의 결과값은 정수이다.
    • 복합 대입 연산자도 지원 (+= -=...)
    • 비교 연산자 (<, >, ==)
    • 비트 연산자
    • 시프트 연산자 (>>, <<)
    • 논리 연산자 (&, |, ^, &^)
  • 부동소수 타입
    • float32, float64(기본)
    • var num = 10.234
    • var num float32 = 10.234 (32bit로 선언할 때)
    • 부동소수점은 소수값을 정확하게 표현할 수 없다. (근사값을 가진다.) 돈처럼 정확한 소수 값이 표현되어야 하는 곳에서는 사용하면 안된다.
    • %(나머지 연산)에 대해서는 정의되어 있지 않음
    • 0이 아닌 부동소수 변수를 0으로 나누면 +-INF가 출력된다.
    • 0으로 설정된 부동소수점 변수를 0으로 나누면 NaN을 반환한다.
    • 가능하면 정수를 사용하고, 필요한 경우만 부동소수점을 사용한다.
  • 복소수 타입
  package main
//
import (
	"fmt"
	"math/cmplx"
)
//
func main() {
	x := complex(2.5, 3.1)
	y := complex(10.2, 2)
//
	fmt.Println(x+y)
	fmt.Println(x-y)
	fmt.Println(real(x))
	fmt.Println(imag(x))
	fmt.Println(cmplx.Abs(x))
}



2.1.5 문자열과 룬 맛보기

문자열

  • 제로 값 : 비어있는 문자열
  • 비교연산자 가능
  • 연결연산자 (+)
  • 불면(immutable)
  • 큰 따옴표

  • 단일 코드 포인트
  • 작은 따옴표
  • int32의 별칭

2.1.6 명시적 타입 변환

  • Explicit vs Implicit
  • 명시적 vs 암시적(암묵적)
    -> Manual vs Automatic

자동 타입 변환

  • 편리하나 변환 규칙이 복잡, 예기치 못한 결과 초래 가능.

Go 는 자동 타입 변환 불허

  • 의도의 명확성 및 가독성 중시 때문
  • 심지어 같은 정수라도, 비트수가 다르면 연산이 안된다.
  • 명시적으로 타입 변환해야 함
    -> 모든 타입 변환 규칙을 외울 필요 없다.

다른 GO 타입을 불리언으로 취급할 수 없다.

  • 조건식은 반드시 비교식으로 작성.

var vs :=

  • 변수 선언 스타일에 따른 의도가 존재.
  • var 키워드
    [SYNTAX]
    var 변수 [타입] = [값 (표현식)] : 상황에따라 타입이나 값을 생략할 수 있다.
    • 값의 타입이 예상가능하면 타입 생략 가능
    • 값을 생략하면 타입의 제로 값이 대입
    • 같은 타입의 여러 변수 또는 다른 타입의 여러 변수 동시 선언 가능
    • 여러 변수의 제로 값 동시 선언 가능
  package main
//
import (
	"fmt"
	"reflect"
)
//
func main() {
	var x = 10
	fmt.Println(x, reflect.TypeOf(x))
}

  • 자동으로 int가 들어갔다.
package main
//
import (
	"fmt"
	"reflect"
)
//
func main() {
	var x int64
	fmt.Println(x, reflect.TypeOf(x))
}

  • 변수 선언시, 초기값을 주지 않았어도 0이 들어갔다.
package main
//
import (
	"fmt"
	"reflect"
)
//
func main() {
	var x bool
	fmt.Println(x, reflect.TypeOf(x))
}

  • 다른 값도 마찬가지이다.
package main
//
import (
	"fmt"
)
//
func main() {
	var x, y= 0, 1
	fmt.Println(x, y)
}

  • 변수 여러개도 한번에 대입이 가능하다.
package main
//
import (
	"fmt"
	"reflect"
)
//
func main() {
	//var x uint8 = 10
	//var y = "hello"
	var x, y = uint8(01), "hello"
	fmt.Println(x, y)
	fmt.Println(reflect.TypeOf(x))
}
  • 변수의 타입이 달라도, 이렇게 대입할 수 있다.
    • 다양한 변수를 한 번에 선언
      • 선언리스트를 괄호로 묶어서
  • := 짧은 선언
    • var 키워드 (X)
    • 타입 (X)
    • :=의 왼쪽에는 기존의 변수가 아닌 새로 생선되는 변수만 올 수 있다. 즉, 처음 선언할 때만 사용하는 것이다.
    • 함수 내에서만 사용 사능, 함수 밖에서는 사용 불가 = Package레벨에서는 사용 불가.
package main
//
import (
	"fmt"
)
//
func main() {
	x := 10
	x, y := 20, "hello"
	//var x = 10
	//var x, y = 20, "hello"	
	fmt.Println(x, y)
}

  • var로 x가 선언이 되었을 때, var x, y =~~ 로 선언하면 x가 이미 선언되었기 때문에 y도 대입이 안된다.
  • x := 10 으로 이미 선언 되었지만, y가 처음선언이 되는 것이기 때문에 :=에서는 x와 y가 같이 바뀐다.
    • 그러나 만약 x와 y 둘다 이미 선언된 변수라면 에러가 난다.
    • 즉, 왼쪽 변수에 새로 선언되는 변수가 하나라도 있다면 := 가 적용되지만, var는 모두 새로 선언되어야 작동한다.

    := 연산자를 피해야 할 때

  • 제로 값으로 변수를 초기화 할 때, var x int와 같이 사용하자, 의도한 제로 값이 할당될 수 있도록 하기 위함이다.
  • 타입이 지정되지 않은 상수나 리터럴이 변수에 할당될 떼, 타입을 지정할 수 있는 var 형식을 사용하자, 타입 변환을 사용하여 값의 타입을 지정하고 := 연산자를 사용하여 x := byte(20)과 같이 사용하는 것은 문제는 없지만, var * byte = 2-으로 사용하는 것이 관용적인 코드를 만들 수 있다.
  • := 연산자는 새로운 변수나 이미 존재하는 변수에 모두 값을 할당하기 때문에, 이미 있는 변수에 값을 할당하려고 의도했던 것이 새로운 변수를 만들게 되는 경우가 발생한다. 이런 상황에서 명시적으로 var 키워드를 사용하여 변수를 새로운 선언으로 명확히 한다면, 이미 있던 변수나 새로운 변수 모두에 할당 연산자(=)를 사용할 수 있다.

2.3 const 사용

  • const는 상수 변수라고 생각하면 된다.
  • 그래서 일종의 리터럴이지만, 한번 변경하면 더이상 변경할 수 없는 값이다.
  • 파이썬에서는 존재하지 않고, 가시적으로SNAKE_CASE로 표시해 상수처럼 사용한다.
  • 상수: 상수 변수
  • 한 번 대입한 값을 변경할 수 없다.
  • 컴파일 시 값이 결정되어야 한다. 즉, 변수를 대입할 수 없다.
  • 리터럴에 이름을 부여하는 방법
package main
//
import (
	"fmt"
)
//
const x int64 = 10
const (
	idKey	= "id"
	nameKey = "name"
)
const z = 20 * 10
//
func main() {
	const y = "hello"
	fmt.Println(idKey, nameKey, z, y)
}

package main
//
import (
	"fmt"
)
//
const x int64 = 10
const (
	idKey	= "id"
	nameKey = "name"
)
const z = 20 * 10
//
func main() {
	const y = "hello"
	z += 10
	fmt.Println(idKey, nameKey, z, y)
}

  • 위 코드에서 const에 변경을 가하면 바로 에러가 출력된다.

2.4 타입 지정 상수와 타입 미지정 상수

  • 프로그래밍 의도가 들어가 있는 것이다.
  • 타입 미지정 상수는 리터럴과 같은 취급
profile
Talking Potato

0개의 댓글