[Go언어]

원종서·2021년 12월 21일
0

go언어

목록 보기
2/2
  • GO 언어의 장점
  1. 정적 타입, 강타입
  2. 컴파일 언어
  3. 가비지 컬렉터
  4. 병행성
  5. 멀티코어 환경 지원
  6. 모듈화 및 패키지 시스템
  7. 빠른 컴파일

정적타입: 자료형을 컴파일 할 때 결정하면
동적타입: 실행할때 결정하면

약타입: 선언한 값의 타입을 바꿀 수 있음, (C언어가 암시적 변환 가능)
강타입: 값 자체가 타입이며, 타입 못바꿈

컴파일언어 :
C, C++, JAVA, C#, GO,
인터프리터언어: Python, Ruby, javaScript

func main(){
	// 변수 선언 예
	var i int
	var s string
    	
       var age int = 10
	// 위와 같음 age := 10
	var name string = "Maria"
    
    // var name <- 자료형을 붙이지 않으면 초기값을 대입해야함.
    
   // 병행 할당
   
	var (
		a1, b1	int = 30,50
		c1, d2  string ="c", "d"
	)
    

변수를 선언하고 사용하지 않으면 컴파일에러가 난다.
이를 방지하기 위해서는 _ = 위에 선언한 변수명

var num int64 =1

unsafe.Sizeof(num) // 8, num의 바이트 수를 리턴

상수

	const constAge int = 999
	const constStr string = "const stirng"
	const canThisTo = "변수 없이도 가능!"
    	const (
		p,q = 10,20
	)

Enum

const (
		Sun = iota +1 //= 0 +1
		Mon		//= 1+1
		Tues		//= 2+1
		Wed		//= 3+1
		Thur		//= 4+1
		Fri
		Sat
		numberOfDays
	)

lota +a 하면 Enum에 첫번째 번호를 a부터 시작.

For

	Loop2 :
		for i:=0; i<3 ;i++{
			for j:= 0; j<3;j++ {
				if j== 2{
					// Loop 와 for문 사이에 어떠한 문법도 들어가면 안댐

					break Loop2
				}
				fmt.Println(i,j)
			}
			
		}

		/*
	for i, j := 0,0 ; i<10 ; i++, j++{
		//error
	}*/

	for i, j := 0,0 ; i<10 ; i, j= i+1,j+2{
		fmt.Println(i,j);
	}

Goto

go 언어는 switch 문에서 case 안에 break를 쓰지 않아도 (쓰지 않아야 함) 자동으로 맞는 조건을 실행하고 switch를 탈출하지만
임의적으로 case 수행 후 밑의 case를 수행하고 싶다면 "fallthrough" 를 사용하면 된다.


func main2(){
	a := 1
	
	if a== 1{
		goto Error1
	}
	if a== 2{
		goto Error2
	}
	if a== 3{
		goto Error1
	}
	Error1:
		Println("Error 1")
       		 return
		
	Error2:
		Println("Error 2")
		return

Error 1

switch i {
		//case 2, 4, 6, 8: 등의  OR 조건식으로도 표현할 수 있음.,
		//case i>=5 && i<=10 등 조건문도 가능함
	}

Array

	var a1 [5]int = [5]{1,2,3,4,5} 
        var b = [5]int {6,7,8,9,10}
	c := [5]int{1,2,3,4,5}
    //크기 5로 지정과 초기화
    
    
    d := [...]int{1,2,3,4,5,6,7,7,123,2}
    //가변인자... 사용  크기 10 할당

	//  배열 d를 e로 복사
	e: = d
    

슬라이스 사용하기

  • 슬라이스는 배열과 같지만, 길이가 고정되지 않아 동적으로 크기가 늘어남, 레퍼런스 타입

  • 슬라이스는 make함수를 사용해 공간을 할당해야 값을 넣을 수 있음

make([]자료형, 길이, 용량)

	var sliceA []int =make([]int,5)
	var sliceB = make([]int,5)
	sliceC := make([]int,10)
    
    sliceWithInit := []int {
		1,2,3,4,5, // 마지막 원소 뒤에 콤바 붙	여줘야함
	}

슬라이스로 (동적 할당) 만든 배열만 append 함수를 쓸 수 있다.

	sliceAppendingA := []int{1,2,3}
	sliceAppendingB := []int{4,5,6}	
	
	// 슬라이드의 원소를 다른 슬라이드로 append 하기 위해서 "추가될 원소를 갖은 슬라이스 배열..." 를  어팬드의 두번째 매개변수에 적어준다.
	sliceAppendingA  = append(sliceAppendingA, sliceAppendingB...)

슬라이스의 요소를 복사할때는 copy(des,ori) 함수를 사용해야한다.

map

  • var varName map[keyType]valueType
  • make 함수를 사용해서 공간을 할당해야함
	var a map[string]int = make(map[string]int)
	var b = make(map[string]int)
	c := make(map[string]int)
    
    d := map[string]string {
		"name" : "jongseo",
		"age" : "25",
	}

선언한 맵에 원하는 키에 대한 값 찾기

	value, ok := d["name"]
	Println(value,ok)
	
	if value, ok := d["name"] ; ok{
		Println(value)
	}else{
		Println(ok)
	}

맵 순회하기


	for key,value := range d{
		Println(key, value)
	}

함수

func FUNCNAME(매개변수 자료형)리턴값자료형 {}

func sum(a int, b int) (r int) {
	r = a+b
	return
}

func sumAndDif(a int , b int) (int, int){
	return a+b, a-b
}

// Go 언어는 한개 이상를 반환할 수 있다.
func main(){
	a := sum(1,2) // a= 3
    sum, dif = sumAndDif(1,2) // 3,-1
}

가변인자를 매개변수로 받는 함수 작성

// func FUNC_NAME(Parameter_name ...data_type) return_type{}


func multiSum(n ...int) int {
	total := 0

	for _ , value := range n {
		total += value
	}
	return total

}

func main(){
	total1 := multiSum(1,2,3,4,5) // 15
    slice := []int{1,2,3,4,5}
    total2 := multiSum(slice...) // 15
}
}

변수에 함수 저장하기

func sumAndDif(a int , b int) (int, int){
	return a+b, a-b
}
func main(){
	var  varFunSum func(a int , b int) (int, int) = sumAndDif
}

함수 맵 형식으로 변수 저장

mapOfVer := map[string]func(a int , b int) int {
		"SUM" : funcName1,
		"DIF" :	funName2,
	}

	Println(mapOfVer["SUM"](1,2))
	

익명 함수

func(s string){
		Println(s)
	}("on")
    
    
anonFunc := func(a int , b int) int {
		return a+b 
	    }(99,2)

Println(anonFunc) // 101

Closer

  • 함수 안에서 함수를 선언 및 정의 할 수 있고 , 바깥쪽 함수에 선언된 변수에도 접근 할 수 있다.

Defer

defer(지연호출) 은 특정 함수를 현재 함수가 끝나기 직전에 실행하는 기능,
// try,finally와 비슷함..
// IO작업할 때 유용 defer file.close();

func hello(){
	Println("Hello")
}

func world(){
	Println("World")
}
func main(){
	// 현재 함수 (main)이 끝나기 직전에 호출
	defer world()
	hello()
	hello()
	hello()

Hello
Hello
Hello
Wolrd

Panic

  • panic()의 매개변수로 전달할 값을 recover() 의 반환값으로 사용하며,
  • recover 함수는 반드시 defer 함수로 작성해야한다.
  • 런타임 에러가 발생 가능한 함수에서는 recover 함수를 지연 함수로 적어주는 것이 좋다

func f(){
	defer func(){
		s := recover()

		fmt.Println(s)
	}()

	panic("Error !!")
}

func main(){
	f()

	Println("Hi~");
}

Error !!
Hi~

구조체

type Rectangle struct {
	width, height int
}
func main(){
	var rect1 Rectangle = Rectangle{10,20}
	rect2 := Rectangle{45,65}
	rect3 := Rectangle{width: 100, height: 200}
}

생성자

go에는 클래스가 없다, 구조체를 클래스처럼 사용해야한다 구조체를 생성자로 생성하는 방법

  • 함수에 매개변수를 전해주면서 함수 내에서 구조체를 만들고 만든 구조체변수의 주소를 반환한다.
  • go언어에서는 지역변수를 계속 참조 하고 있으면
    스코프를 벗어나도 변수가 해제되지 않는다.

func NewRectangle(width, height int) *Rectangle {
	newR := Rectangle{width,height}
	return &newR
}

메서드

클래스가 없기 때문에 메서드도 없다, 구조체를 이용해 메서드를 정의하는 방법은
구조체 밖에서 함수를 정의한다


// func(리시버명 구조체 타입) 함수명() 리턴값{}
//리시버명 구조체 타입= 연결할 구조체 지정

// Rectangle 구조체에 area메서드를 정의한다.
func (rect *Rectangle) area() int {
	return rect.height * rect.width;
}

func main(){

	rectWithMethod := Rectangle{10,20}
	var i  = rectWithMethod.area() // 200
}

상속



type Person struct{
	name string
	age int
}

type Student struct{
	//1. p	Person // 학생 구조체 안에 사람 구조체를 필드로 갖고 있음 , Has-a 
	Person //2. <- ls-a 관계 , 
	school string
	grade int
}

func main(){
	var s Student
	s.name ="Jongseo"
    s.age = 25
	s.school = "sejongUniv"
    s.grade = 4
	fmt.Println(s)
}

{{Jongseo 25} sejongUniv 4}

GoRoutine

함수를 호출할때 go키워드를 붙이면, 고루틴으로 실행 ,
고루틴으로 hello를 실행하면, main함수와 동시에 실행되기 때문에 hello()안의 출력문이 시작하기 전에 main 함수가 끝나버린다.
*/
func main(){
	runtime.GOMAXPROCS(runtime.NumCPU())
	Println(runtime.GOMAXPROCS(0))

	s := "Hello ,world"
	// 클로저를 고루틴으로 실행할 때 반복문에 의해 바뀌는 변수는 반드시 매개변수로 넘겨준다.
	// 즉 매개변수로 념겨주는 시점에 해당 변수의 값이 복사됨으로 고루틴이 생성될 때 그대로 사요할 수 있다.
	for i:=0; i<100;i++{
		go func(i int){
			Println(s,i)
		}(i)
	}

	Scanln()
}

Chanel

채널은 고루틴끼리 데이터를 주고받고, 실행 흐름을 제어한다.
채널 자체는 값이 아닌 래퍼런스 타입

채널 사용 형식
make(chan DATA_TYPE)

채널을 매개변수로 받을때
DATA_NAME chan DATA_TYPE

func sumWithChanel(a int, b int , c chan int){
	c <- a+b
 }
// 다음은 채널의 버퍼가 가득 차면 값을 꺼내서 출력함.
func main(){
	runtime.GOMAXPROCS(1)

	done := make(chan bool,2) // 버퍼가 2개인 비동기 채널 생성
	count := 4

	// 버퍼 사이즈가 2이니까
	// go 루틴에서 2개(0,1)을 보내고 main 반복문에서 2개(0,1)을 받아 출력한다 채널에 있떤 두개의 데이트를
	//출력하면 버퍼는 비기 때문에 go루틴에서 다시 채널에 데이터 두개를 채운다

	go func(){
		for i:= 0 ; i<count ; i++{
			done <- true
			Println("고루틴 : ",i)

		}
	}()

	for i := 0; i<count ;i++{
		<-done
		Println("main func : ",i);
	}

}*/
// range 와 close 사용하기
func main(){
	c:= make(chan int)

	go func(){
		for i :=0 ; i<5; i++{
			c<-i
		}
		Println("final ?")
		close(c)
	}()
		//	반복문에서 range 키워드를 사용하면 채널이 닫힐 때까지 반복하면서 값을 꺼냄
		// 여기서는 동시에 고루틴 안에 채널 c에 0부터 4까지 값을 보낸 뒤 close를 사용하여 채널을 닫는다.
		// 이렇게 하면 range로 0부터 4까지 꺼내고 값을 출력 한 후 반복문 종료
	for i:= range(c){
		if i==0 {
			// 채널이 열려있을때
			a, ok := <-c
			Println(a,ok)
		}
		Println(i)
	}

	//채널 닫혔을때
	a, ok := <-c
	Println(a,ok)


}
// 보내기 전용 및 받기 전용 채널 사용하기

// chan <- DATA_TYPE : Send only
// <- chan DATA_TYPE : Read only
func receiveOnlySum(a, b int) <-chan int {
	out := make(chan int)
	go func(){
		out <- a+b
	}()

	return out
}

// 채널만 사용해서 값 더하기
func onlyChanelNum(a,b int) <-chan int{
	out := make(chan int) 
	go func(){
		out<- a
		out<- b
		close(out)
	}()

	return out
}

func onlyChanelSUm(c <- chan int) <-chan int {
	out := make(chan int)
	go func(){
		r:=0
		for i:= range c{
			r= r+i
		}
		out <- r
	}()

	return out
}

func main(){
	c := onlyChanelNum(1,2)
	out := onlyChanelSUm(c)

	Println(<-out)
}

unc main(){
	// 여러 채널을 손쉽게 사용할 수 있도록 select문 제공
	
	intChanel:= make(chan int)
	stringChanel:= make(chan string)

	go func(){
		for{ // 무한루프
			 intChanel <- 10
			 time.Sleep(100 * time.Millisecond)
		}
	}()

	go func(){
		for {
			stringChanel <- "Hello, world"
			time.Sleep(time.Millisecond * 500)
		}
	}()

	go func(){
		for {
			select {
				// case <- 채널1:
				case i := <- intChanel:
					Println("int Chanel : ",i)

				case s := <- stringChanel:
					Println("string Chanel : ", s)
					
				case <-time.After(50*time.Millisecond):
					Println("Time out")
			}
		}
	}()

	time.Sleep(10 * time.Second)
}

string Chanel : Hello, world
int Chanel : 10
Time out
Time out
int Chanel : 10
Time out
int Chanel : 10
Time out
int Chanel : 10
Time out
int Chanel : 10
Time out
...

0개의 댓글