golang 스터디 1주차 (변수 / 연산자)

2023-11-26
14min
Golang
INFO

Tucker 의 Go언어 프로그래밍 스터디 내용 정리입니다.

이 글은 묘공단 스터디 뭐시기...

Chapter 01. 컴퓨터의 원리


1.1 비트의 탄생과 트랜지스터


1.1.1 트랜지스터

트랜지스터는 연산을 수행하는 가장 기본이 되는 소자. 트랜지스터는 성질이 다른 2가지 실리콘인 N형과 P형을 겹처서 만든다.

이 트랜지스터는 on / off 의 개념을 갖는다. 이 on / off 를 숫자 2진로 0 또는 1로 표현한다.

1.1.2 진수

컴퓨터는 1과 0 두 숫자를 사용해서 모든 수를 표현함.

트랜지스터 1개로 0, 1 이 표현이 가능. 따라서 2진법으로 10011 이라는 숫자를 표현하기 위해서는 5개의 트랜지스터가 필요하다.

트랜지스터 하나로 표현한 2진법 한자리를 1bit 라고한다.

단위 정리

  • 1 byte = 1bit
  • 1 kb = 1,024 byte
  • 1 mb = 1,024 kb
  • 1 gb = 1,024 mb
  • 1 tb = 1,024 gb
  • 1 pb = 1,024 tb
  • 1 zb = 1,024 pb

1.2 트랜지스터에서 계산기로

계산을 하기 위해서는 논리 소자를 알아야함. 대표적인 논리소자로는 AND, OR, XOR, NOT 가 있다.

AND

  • 두 입력이 모두 1 이면 1을, 하나라도 0 이면 0을 반환

OR

  • 두 입력 중 하나라도 1 이면 1을, 모두 이면 0 을 반환

XOR

  • 두 입력이 서로 다르면 1을, 같다면 0 을 반환

NOT

  • 입력이 하나고 0 이면 1을, 1이면 0 을 반환

1.2.2 논리 소자로 사칙연산 구현하기

1비트 가산기란 1비트 입력 2개를 더하는 회로 사자.

AND 와 XOR 논리 소자로 회로를 만들면 덧셈 기승을 구현할 수 있다.

  • AND: 자리 올림
  • XOR: 합의 결과

1.3 계산기에서 컴퓨터로


1.3.2 컴퓨터의 완성: 폰 노이만 구조


위키피디아 사진위키피디아 사진

중앙에 연산을 담당하는 중앙 처리 장치인 CPU, 기억 장치인 Memory 그리고 입력 / 출력 장치로 구성됨

폰 노이만 구조는 모든 현대 컴퓨터에서 사용되는 기본적인 구조

1.4 컴퓨터 동작 원리

컴퓨터는 크게 아래의 장치들로 구성됨

  • CPU
  • 메모리
    • 휘발성 메모리
    • 비휘발성 메모리
      • 디스크
  • 입출력 장치

프로그램을 실행하면 컴퓨터는 아래의 4단계 동작을 수행

  1. 프로그램 로그
    • 프로그램이 실행되면 실행 파일을 메모리 에 복사.
    • 디스크에 올리면 너무 느림. 반면 램은 디스크보다 용량은 작지만 속도가 빠름
    • 따라서 프로그램 코드와 필요한 데이터를 메모리로 복사하고 실행
  2. 데이터로드 및 캐싱
    • 모든 명령은 cpu 에 의해 실행됨
    • cpu 가 연산을 처리하려면 필요한 데이터를 가져와야한다.
    • 이를 위해서 cpu 내부에는 cache 라는 별도 메모리 공간을 가지고 있다.
    • 램 보다도 적은 공간이지만 속도는 많이 빠르다.
    • 따라서 메모리에서 연산에 필요한 데이터를 캐시로 복사해 오고 연산 시작.
  3. 연산 및 저장
    • 캐시에 데이터가 준비되면 cpu 는 연산에 사용할 데이터를 레지스터로 복사한다.
    • 레지스터는 실제 연산이 수행되는 특수한 데이터 공간

Chapter 02. 프로그래밍 언어


2.1 초창기 프로그래밍 언어


컴퓨터가 알 수 있는건 오직 0과 1 밖에 없다. 따라서 컴퓨터가 알아들을 수 있는 기계어 가 필요하다.

0과 1을 이용해서 단어 를 만든다고 생각하면 될듯. 예를 들어 0011 이라는 숫자가 있다면 이 숫자를 덧셈 이라는 명령어로 변환 후 실행

초창기에는 천공카드에 구멍을 뚫는것으로 이 단어들을 표현.

2.2 어셈블리어의 등장

ADD 3 4 라는 표현을 0011 0011 0100 으로 변환해주는 프로그램. 이런게 어셈블리어.

어셈블리어는 기계어와 1:1로 대응되는 언어

2.3 고수준 언어

어셈블리어는 혁신이었지만 그마저도 사용하기 어려웠음. 따라서 고수준의 언어가 등장

2.3.1 고수준 언어의 실행 과정

어떤 프로그래밍 언어이로 작성하든, 컴퓨터가 명령을 실행하기 위해서는 결국 기계어로 변환이 되어야한다. 어셈블리어는 코드와 기계어가 1:1 매칭 괴기 때문에 변환 과정이 매위 쉽고 빠르다.

하지만, 고수준 언어는 기계어로 바로 번역이 되지 못하기 때문에 기계어로의 변환 작업이 필요하고, 이 변환을 해주는 프로그램을 컴파일러라고 한다.

2.4 프로그래밍 언어 구분


2.4.1 정적 컴파일 언어 vs 동적 컴파일 언어

정적 컴파일 언어

  • 미러 기계어로 변환해두었다가 사용하는 방식
  • 보통 실행파일
  • 실행할 때 변환 과정이 없기 때문에 빠르다.

동적 컴파일 언어

  • 실행 시점에 기계어로 변환하는 방식의 언어
  • 실행하는 시점에 변환하기 때문에 느리다.

느린데 왜 동적 컴파일 언어가 있어?

  • 칩셋과 운영 체제마다 0과 1로 된 바이너리 코드를 표현하는 방식이 다름. 따라서 기계어로 변환할 때 각 칩셋에 맞게 변환해줘야ㅐ한다.
  • 하지만 동적 컴파일 언어는 이런 번거로움 없이 모든 플랫폼에서 실행됨.
  • 즉, 속도를 희생하고 범용성을 잡음

Chatper 03. 가볍게 Go 입문하기


코드가 실행되기 까지 5단계를 거쳐야한다.

  1. 폴더 생성
    • Go 언어에서 모든 코드는 패키지 단위로 작성됨
    • 캍은 폴더에 위치한 .go 파일은 모두 같은 패키지에 포함되고, 패키지 명으로 폴더명을 사용
    • goproject/hello/extra
      • hello 폴더안에 든 .go 파일은 hello 패키지
      • extra 폴더안에 든 .go 파일은 extra 패키지
  2. .go 파일 생성 및 작성
  3. Go 모듈 생성
    • go mod init goproject/hello
  4. 빌드
  5. 실행

3.4. Hello Go World 코드 뜯어보기

go
package main // 1 import "fmt" // 2 func main() { //3 fmt.Println("Hello Go") }
go
package main // 1 import "fmt" // 2 func main() { //3 fmt.Println("Hello Go") }
  1. package main
    • 패키지 선언은 이 코드가 어떤 패키지에 속하는지 알려줌
      • package main 은 main 패키지에 속함
    • main 패키지는 프로그램의 시작과 끝음 담당
    • main 패키지로 선언했다면 내부에 main() 함수를 구현해야함
  2. import "fmt"
    • fmt 패키지를 불러옴
  3. func main()
    • 프로그램의 시작과 끝.

Chapter 04. 변수


변수란 프로그래밍에서 변수는 값을 저장하는 메모리 공간을 가리킴

변수를 사용하려면 먼저 변수를 선언해야한다.

go
var a int = 10;
go
var a int = 10;
  • var: 변수 선언 키워드
  • a: 변수명
  • int 타입
  • 10: 초깃값

4.3 변수에 대해 더 알아보기

4.3.1. 변수의 4가지 속성

  • 이름: 개발자는 이름을 통해 저장된 메모리 공간에 접근
  • 값: 변수가 가리키는 메모리 공간에 저장된 값
  • 주소: 변수가 저장된 메모리 공간의 시작 주소
  • 타입: 변수의 형태

4.3.2. 변수는 이름을 갖는다

프로그래머는 변수명을 사용해 값이 저장된 메모리 공간에 접근하고 수정할 수 있다. 변수명을 지을 때 따라야하는 규칙은 아래와 같다.

  • 문자, _, 숫자를 사용해 지을 수 있지만, 첫 글자는 반드시 문자_ 로 시작해야한다.
  • _ 를 제외한 다른 특수문자는 포함 할 수없다.

4.3.3 변수는 타입을 갖는다

타입은 공간의 크기를 나타낸다. 변수는 메모리 주소를 가리킨다고 이전에 말했다. 가리키는 주소는 시작점이다. 해당 변수가 차지하는 메모리의 끝은 타입의 크기를 이용해 알아낸다.

변수타입의 종류는 여기를 참고하자.

4.4 변수 선언의 다른 형태


go 언어에서는 편의를 위해 여러 형태의 변수 선언을 지원한다.

go
func main { var a int = 3 // 기본 var b int // 초깃값 생략. 초깃값은 타입별로 다르다. var c = 4 // 타입 생략. 변수 타입은 우변 값의 타입으로 됨 d := 5 // 선언 대입문. var 키워드와 타입 생략. }
go
func main { var a int = 3 // 기본 var b int // 초깃값 생략. 초깃값은 타입별로 다르다. var c = 4 // 타입 생략. 변수 타입은 우변 값의 타입으로 됨 d := 5 // 선언 대입문. var 키워드와 타입 생략. }

4.5 타입 변환

int 와 int64 처엄 같은 정수라도, 타입이 다르면 계산이 안된다. 이 때 필요한게 타입 변환

go
a := 3 // int var b float64 = 3.5 c := a * b // error. int 와 flat64는 다른 타입이다. 따라서 연산 불가능
go
a := 3 // int var b float64 = 3.5 c := a * b // error. int 와 flat64는 다른 타입이다. 따라서 연산 불가능
go
a := 3 // int var b float64 = 3.5 c := a * int(b) // float64 타입을 강제로 int 로 형변환. 대신 b 는 3.5가 아니게 된다.
go
a := 3 // int var b float64 = 3.5 c := a * int(b) // float64 타입을 강제로 int 로 형변환. 대신 b 는 3.5가 아니게 된다.

4.6 변수의 범위

변수의 범위는 기본적으로 블록 스콥이다.

Chapter 05. fmt 패키지를 이용한 텍스트 입출력


5.1 표준 출력

fmt 패키지는 3가지 표준 출력 함수를 제공

  • Print()
    • 함수 입력값 출력
  • Println()
    • 함수 입력값을 출력하고 개행
  • Printf()
    • 서식에 맞도록 입력값들을 출력
    • 서식지정자는 여기서 확인
    • 어떤 서식을 사용해야할지 모르겠어면 일단 %v 사용
go
package main import "fmt" func main() { var a int = 10 var b int = 20 var f float64 = 123123.123 fmt.Print("a: ", a, "b: ", b) // a: 10b: 20 fmt.Println("a: ", a, "b: ", b, "f: ", f) // a: 10 b: 20 f: 123123.123 }
go
package main import "fmt" func main() { var a int = 10 var b int = 20 var f float64 = 123123.123 fmt.Print("a: ", a, "b: ", b) // a: 10b: 20 fmt.Println("a: ", a, "b: ", b, "f: ", f) // a: 10 b: 20 f: 123123.123 }

5.2 표준 입력


표준 입력은 입력 장치에서 데이터를 가져온다. ㅇ리반적으로 키보드가 표준 입력 장치가 됨

  • Scan()
    • 표준 입력에서 값을 입력받음
  • Scanf()
    • 서식 형태로 값을 입력 받음
  • Scanln()
    • 한 줄을 읽어서 값을 입력 받음

Chapter 06. 연산자

연산자 종류는 여기를 참고하자

6.1 산술 연산자

산술 연산

  • 산술 연산자는 숫자 연산을 하는 연산자다. 사칙 연산 / 비트 연산 / 시프트 연산이 여기에 속함
  • Go언어에서 모든 연산자의 각 항의 타입은 항상 같아야한다. 따라서 결과 타입도 항상 인수의 타입과 동일하다.
  • 비트 연산자는 정수만이 피연산자가 될 수 있다.

6.2 비교 연산자

비교 연산

  • 양변을 비교해 조건을 만족하면 true 못할 경우 false 를 반환하는 연산자
  • 실수끼리의 비교 연산에서 에러 발생할 수 있음. 이를 대비하기 위해 작은 오차 무시하기 실수의 지수부 표현에서 가장 오른쪽 비트값 하나만큼의 오차를 무시