Golang Start

이민기·2022년 1월 24일
1

GO

목록 보기
1/15
post-thumbnail

Golang

Variable & Type

  • Go는 Type language이기 대문에 선언할 때 타입도 같이 선언 해주어야 한다
const name string = "foden"  // Constant
var name string = "kevin" // Variable

name := "Toure" // shortCut 함수 안에서는 이렇게 작성하여 자동으로 타입을 설정 가능, 변수에만 가능
💡 shortCut은 function안에서만 사용 가능하다
  • function을 만들 때 arguments들에게도 타입을 지정해 주어야 하고, function의 return타입도 지정해 주어야 한다
func multiply (a int, b int) int{
	return a*b
}
  • Go는 1개의 func에서 2개 이상도 retrun할 수 있다
  • _(underScore)을 이용해서 value를 무시할 수 있다.
  • 여러개의 args를 받을 때에는 ...을 사용한다
  • defer를 이용해서 함수가 종료된 후 코드를 실행시킬 수 있다
func lenAndUpper (name ...string) (int,string){
	defer fmt.Println("함수가 종료될 때 코드가 실행")
	return len(name), strings.ToUpper(name)
}

func main(){
	totalLen, upperName := lenAndUpper("mingi") // 출력시 5, MINGI
	totalLength, _ := lenAndUpper("abc")  //출력시 3
}

For

  • For 문
   func add(numbers ...int) int{
       total := 0;
       for i:=0; len(numbers)>i; i++ {
          total += numbers[i]
      }
      return total
   } 
   
	func main() {
	result := add(1, 2, 3, 4, 5, 6)
	fmt.Println(result)
}
  • For Range

    💡 JavaScript의 forEach와 비슷하다 range는 index를 함께작동한다
    
func add (numbers...int) int {
  	total := 0;
   	for index, number := range numbers { //index를 사용하지 않을 때는 _를 이용해서 ignore가능하다
   		total += number
   	}
   	return total
   }
    
func main() {
   	result := add(1, 2, 3, 4, 5, 6)
   	fmt.Println(result)
 }
    
Label을 이용하여 중첩된 for문을 나올 수 있다
func isOnMempool(UTxOut *UTxOut) bool {
   	exists := false
    Outer:  //label선언
   	for _, tx := range Mempool.Txs {
   		for _, input := range tx.TxIns {
   			exists = input.TxID == UTxOut.TxID && input.Index == UTxOut.Index
			break Outer  //for문이 중첩되었을 때 label을 이용하면 조건이 만족했을때 label로 빠져나간다.
		}
	}
	return exists
}

If ~ else

  • variable expression : if else, switch를 사용할 때 변수를 만들어서 바로 사용가능하다
func canIDrink(age int) bool {
	if koreanAge := age + 2 ; koreanAge < 20 { //;가 끝나는 부분부터 조건문의 조건이다
		return false
	} return true
}

func main() {
	fmt.Println(canIDrink(17))
}
💡 Go에서는 if문이 끝나는 마지막 else는 생략하고 사용해도 된다.

Switch

  • Switch문에서도 역시 variable expression사용 가능하다
func canIDrink(age int) bool {
	switch koreanAge := age + 2 ; koreanAge { 
		case koreanAge < 21:
			return false
		default:
			return true
	} 
}

func main() {
	fmt.Println(canIDrink(17))
}

Pointer

  • Pointer - 메모리값에 직접 접근하기
  • & : 변수의 메모리 주소값을 보기
  • * : 메모리 주소값의 저장된 값을 보기
func main() {
	a := 2  // a에 2를 저장
	b := &a  // b에 a의 메모리 주소값을 저장
	fmt.Println(*b) //b에 저장된 메모리주소값 안에 저장된 값을 출력 / 출력값: 2
	*b = 20
	fmt.Println(a) // 출력값 : 20
}

Array & Slice

func main (){
	colors := [3]string{"black","white","blue"} // array 선언할 때 크기도 지정
	names := []string{"Kevin","Foden","Yaya"} // slice 선언할 때 크기를 지정x
	names = append(names, "Mingi") //slice에 argument를 추가 할 때는 append()를 사용
💡 slice에 추가할 때 사용하는 append()는 slice를 수정하는 것이 아닌 새로운 slice를 반환한다

Map & Struct

  • map은 JavaScript의 Object와 유사하다
type person struct {
	name string
	age int
	favFood []string
}

func main() {
	mingi := map[string]string{"name":"mingi","age":"27"} 
	//map은 [key]value의 타입과 함께 선언하고 value값이 처음 선언된 타입이 아닌 타입은 사용할 수 없다.
	favFood := []string{"pizza","icecream"}
	leeMingi := person{name : "mingi", age : 27, favFood: favFood}
	//함수 밖에 struct을 선언 해주고 사용한다
}
  • empty map을 초기화해서 선언할 때는 make()라는 함수를 사용한다
var results = make(map[string]string)
💡 이렇게 하지 않을 경우 map은 nil이 될 수 있다. => nil이 된 map에는 아무 값도 넣을 수 없다
//Account struct...
type Account struct{
	owner string
	balance int
}

export 할 때 export하는 것의 이름을 시작으로 comment를 작성해 놓아야 한다

Public & Private

  • public으로 설정하고 싶으면 첫 글자를 Uppercase(대문자)로 사용한다
  • private으로 설정하고 싶으면 첫 글자를 Lowercase(소문자)로 사용한다
type Person struct{  //public
	Name string  //public
	age int  // private
}

Receiver & Method

package accounts

//Account struct
type Account struct {
	owner   string
	balance int
}

//NewAccount creates Account
func NewAccount(owner string) *Account {
	account := Account{owner: owner, balance: 0}
	return &account
}

//Deposit x amount on your account
func (a *Account) Deposit(amount int) { 
// (a *Account)를 pointer receiver라고 한다. a를 수정해야하기 때문에 pointer를 사용해서 수정했다
	a.balance += amount  

}

//Balance of your account
func (a Account) Balance() int {    // a는 Account타입이다
	return a.balance
}
💡 receiver는 struct의 첫 글자를 따서 소문자로 이름을 지어야 한다

Error

  • error는 error와 nil 두 가지 value가 있다
💡 nil은 JavaScript의 none, null과 비슷한 의미이다.
  • Go에는 Exception이 따로 없으며 error를 모두 직접 handling해야 한다.
  • Error의 변수이름은 err***로 시작해야한다
var errNoMoney = errors.New("Can't withdraw")
  • panic은 error이긴 하지만 compiler가 모르는 error이다

Go Routines

  • Goroutines: 다른 함수와 동시에 실행시키는 함수
func main() {
	countdown("Foden")
	go countdown("Kevin")
	//이렇게 사용하면 두 함수가 동시에 실행된다
}

func countdown (person string) {
	for i:=0; i>5; i++ {
		fmt.Println(person," say " i)
		time.Sleep(time.Second)
	}
}
💡 goroutines를 이용한 함수는 실행 함수로 처리 되지 않는다 따라서 두 개의 함수 모두 go를 사용하면 main function에서 실행할 함수가 없으므로 바로 종료된다.

Cnannel

  • Channel은 goroutine과 main함수 사이에서 정보를 전달하기 위한 방법이다
func main() {
	c:= make(chan bool)  //channel 선언, 받을 데이터 타입도 같이 선언해야한다.
	people := [2]string{"Kevin","Foden"}
	for _, person := range people {
		go isPlayer(person, c)
	}
	for i:=0; i<len(people); i++ {
		fmt.Println(<-c) //channel로 받은 데이터 출력
	}
}

func isPlayer (person string, c chan bool) { //받을 argumets로 channel도 넣는다
	time.Sleep(time.Second * 5)
	fmt.Println(person)
	c <- true // channel로 데이터 보내기
}
📌 main function에서 goroutines를 제외하고는 Println()밖에 실행할 수 없지만 c ←는 channel을 통해 받을 데이터를 의미하기 때문에 바로 종료되지 않고 데이터를 받은 후 출력한 뒤에 종료된다.

📌 ←c channel을 받는 이 부분은 blocking operation이라고도 한다

📌 DeadLock - blockingOperation에 데이터가 들어오지 않아 unBlock되지 않는것.

📌 channel을 닫을 때는 close(c)를 사용한다

func hitURL (url string, c chan<- string) { //이렇게 지정하면 sendOnly가 된다.
	fmt.Println(<-c) //channel을 보낼 수 밖에 없는 func이기 때문에 오류가 발생한다
}

func receive (c <-chan string) {}  //이건 receiveOnly이다

Buffered Channel

  • bufferedChannel - channel에 공간을 부여하고, 공간에 data가 차기 전에는 block하지 않는 channel
package main

import (
	"fmt"
	"time"
)

func send(c chan<- int) {
	for i := range [5]int{} {
		fmt.Printf(">> sending %d <<\n", i)
		c <- i
		fmt.Printf(">> sent %d <<\n", i)
	}
	close(c)
}

func receive(c <-chan int) {
	for {
		time.Sleep(3 * time.Second)
		a, ok := <-c
		if !ok {
			fmt.Println("we are done.")
			break
		}
		fmt.Printf("|| received %d ||\n", a)
	}
}
func main() {
	c := make(chan int, 3)  //channel을 만들 때 공간의 크기도 같이 선언
	go send(c)
	receive(c)
}
 출력	

 >> sending 0 <<
 >> sent 0 <<
 >> sending 1 <<
 >> sent 1 << 
 >> sending 2 << 
 >> sent 2 << 
 >> sending 3 << 
 || received 0 || 
 >> sent 3 <<
 >> sending 4 << 
 || received 1 ||
 >> sent 4 <<
 || received 2 || 
 || received 3 ||
 || received 4 ||
 we are done.
 
func main() {
	c := make(chan int)
	go send(c)
	receive(c)
}
출력
 
 >> sending 0 << 
 || received 0 ||
 >> sent 0 <<
 >> sending 1 <<
 || received 1 ||
 >> sent 1 <<
 >> sending 2 <<
 || received 2 ||
 >> sent 2 <<
 >> sending 3 <<
 || received 3 ||
 >> sent 3 <<
 >> sending 4 <<
 || received 4 ||
 >> sent 4 <<
 we are done.
 

Named Return

  • named retrun - 반환 값의 이름을 타입과 함께 명시하는 방법
func restoreKey() (key *ecdsa.PrivateKey) {  //key라는 값을 반환할 것
	keyAsBytes, err := os.ReadFile(fileName)
	utils.HandleErr(err)
	key, err = x509.ParseECPrivateKey(keyAsBytes)  
	 //key라는 변수는 함수 선언과 함께 초기화 되었으므로, :=로 선언이 아닌 =를 사용해서 update
	return  //return시 name을 선언할 필요 x
}

💡 한 눈에 볼 수 있는 작은 function에만 사용하는 것이 그나마 좋다.

iota

  • iota - type과 value를 자동생성
const (
	MessageNewestBlock MessageKind = iota // MessageKind = 0
	MessageAllBlocksRequest  // MessageKind = 1
	MessageAllBlocksResponse  // MessageKind = 2
)
profile
블로그를 옮기는 중입니다. https://min71.dev

0개의 댓글