Golang 튜토리얼: 초보자를 위한 Go 프로그래밍 언어 배우기

바둑은 무엇입니까?

Go (Golang이라고도 함)은 Google에서 개발한 오픈 소스 프로그래밍 언어입니다. 정적 타입 컴파일 언어입니다. Go는 동시 프로그래밍을 지원하여 여러 프로세스를 동시에 실행할 수 있습니다. 이는 채널, 고루틴 등을 사용하여 달성됩니다. Go 언어에는 가비지 콜렉션이 있으며, 가비지 콜렉션 자체가 메모리 관리를 수행하고 함수의 지연된 실행을 허용합니다.

우리는 Go 언어 배우기 튜토리얼에서 Golang의 모든 기본 사항을 배울 것입니다.

GO 다운로드 및 설치 방법

단계 1) We Buy Orders 신청서를 클릭하세요. https://golang.org/dl/. 해당 OS에 맞는 바이너리를 다운로드하세요.

단계 2) Double 설치 프로그램을 클릭하고 실행을 클릭합니다.

단계 3) 다음을 클릭하십시오.

단계 4) 설치 폴더를 선택하고 다음을 클릭합니다.

단계 5) 설치가 완료되면 완료를 클릭하십시오.

단계 6) 설치가 완료되면 터미널을 열고 다음을 입력하여 확인할 수 있습니다.

go version

그러면 설치된 Go 버전이 표시됩니다.

첫 번째 Go 프로그램 – Go Hello World!

StudyGo라는 폴더를 만듭니다. 이 Go 언어 튜토리얼에서는 이 폴더 안에 Go 프로그램을 만듭니다. Go 파일은 확장자로 생성됩니다. .가다. 다음 구문을 사용하여 Go 프로그램을 실행할 수 있습니다.

go run <filename>

first.go라는 파일을 생성하고 아래 코드를 추가한 후 저장합니다.

package main
import ("fmt")

func main() {
	fmt.Println("Hello World! This is my first Go program\n")
}

터미널에서 이 폴더로 이동하세요. 명령을 사용하여 프로그램을 실행하십시오.

먼저 달려가.go

출력된 인쇄를 볼 수 있습니다.

Hello World! This is my first Go program

이제 위의 프로그램에 대해 논의해 보겠습니다.

package main – 모든 Go 언어 프로그램은 패키지 이름으로 시작해야 합니다. Go를 사용하면 다른 Go 프로그램에서 패키지를 사용할 수 있으므로 코드 재사용이 지원됩니다. Go 프로그램의 실행은 main이라는 패키지 내부의 코드로 시작됩니다.

import fmt – 패키지 fmt를 가져옵니다. 이 패키지는 I/O 기능을 구현합니다.

func main() – 프로그램 실행이 시작되는 함수입니다. 메인 함수는 항상 메인 패키지에 위치해야 합니다. main() 아래 { } 안에 코드를 작성할 수 있습니다.

fmt.Println – fmt의 Println 기능을 통해 화면에 텍스트를 인쇄합니다.

참고: 이 Go 튜토리얼의 아래 섹션에서 코드 실행/실행을 언급하는 것은 확장자가 .go인 파일에 코드를 저장하고 구문을 사용하여 실행한다는 의미입니다.

    go run <filename>

데이터 타입

유형(데이터 유형)은 변수에 저장된 값의 유형, 함수가 반환하는 값의 유형 등을 나타냅니다.

Go 언어에는 세 가지 기본 유형이 있습니다.

숫자 유형 – 정수, 부동 소수점 및 복소수 값을 포함하는 숫자 값을 나타냅니다. 다양한 숫자 유형은 다음과 같습니다.

int8 – 8비트 부호 있는 정수입니다.

int16 – 16비트 부호 있는 정수입니다.

int32 – 32비트 부호 있는 정수입니다.

int64 – 64비트 부호 있는 정수입니다.

uint8 – 8비트 부호 없는 정수입니다.

uint16 – 16비트 부호 없는 정수입니다.

uint32 – 32비트 부호 없는 정수입니다.

uint64 – 64비트 부호 없는 정수입니다.

float32 – 32비트 부동 소수점 숫자.

float64 – 64비트 부동 소수점 숫자.

complex64 – float32 실수부와 허수부를 가짐.

complex128 – float32 실수부와 허수부를 가짐.

문자열 유형 – 바이트(문자) 시퀀스를 나타냅니다. 문자열 연결, 하위 문자열 추출 등과 같이 문자열에 대해 다양한 작업을 수행할 수 있습니다.

부울 유형 – true 또는 false의 2가지 값을 나타냅니다.

골랭 인터페이스

골랭 인터페이스 객체의 동작을 구현하기 위해 Type에서 사용하는 메서드 시그니처 모음입니다. Golang 인터페이스의 주요 목표는 이름, 인수 및 반환 유형이 포함된 메서드 서명을 제공하는 것입니다. 메소드를 선언하고 구현하는 것은 Type에 달려 있습니다. Golang의 인터페이스는 "interface"라는 키워드를 사용하여 선언할 수 있습니다.

변수

변수는 일종의 값을 저장하는 메모리 위치를 가리킵니다. 아래 구문의 type 매개변수는 메모리 위치에 저장될 수 있는 값의 유형을 나타냅니다.

변수는 구문을 사용하여 선언할 수 있습니다.

    var <variable_name> <type>

특정 유형의 변수를 선언하면 해당 유형의 모든 값에 변수를 할당할 수 있습니다.

다음을 사용하여 선언 자체 중에 변수에 초기 값을 지정할 수도 있습니다.

    var <variable_name> <type> = <value>

초기값으로 변수를 선언하면 할당된 값의 유형에서 변수의 유형을 유추합니다. 따라서 다음 구문을 사용하여 선언하는 동안 유형을 생략할 수 있습니다.

    var <variable_name> = <value>

또한 다음 구문을 사용하여 여러 변수를 선언할 수 있습니다.

    var <variable_name1>, <variable_name2>  = <value1>, <value2>

이 Go 튜토리얼의 아래 프로그램에는 변수 선언에 대한 Golang 예제가 있습니다.

 
package main
import "fmt"

func main() {
    //declaring a integer variable x
    var x int
    x=3 //assigning x the value 3 
    fmt.Println("x:", x) //prints 3
    
    //declaring a integer variable y with value 20 in a single statement and prints it
    var y int=20
    fmt.Println("y:", y)
    
    //declaring a variable z with value 50 and prints it
    //Here type int is not explicitly mentioned 
    var z=50
    fmt.Println("z:", z)
    
    //Multiple variables are assigned in single line- i with an integer and j with a string
    var i, j = 100,"hello"
    fmt.Println("i and j:", i,j)
}

출력은

x: 3
y: 20
z: 50
i and j: 100 hello

Go 언어는 또한 다음을 사용하여 var 키워드를 생략하여 값이 있는 변수를 선언하는 쉬운 방법을 제공합니다.

    <variable_name> := <value>

당신이 사용했다는 점에 유의하십시오 := 대신 =. 이미 선언된 변수에 값을 할당하기 위해 :=를 사용할 수는 없습니다. :=는 값을 선언하고 할당하는 데 사용됩니다.

다음 코드를 사용하여 assign.go라는 파일을 만듭니다.

package main
import ("fmt")

func main() {
	a := 20
	fmt.Println(a)

	//gives error since a is already declared
	a := 30
	fmt.Println(a)
}

go run 할당.go를 실행하여 결과를 다음과 같이 확인하세요.

./assign.go:7:4: no new variables on left side of :=		

초기값 없이 선언된 변수는 숫자 유형의 경우 0, 부울의 경우 false, 문자열의 경우 빈 문자열을 갖습니다.

상수

상수 변수는 한번 할당되면 값을 변경할 수 없는 변수입니다. Go 프로그래밍 언어의 상수는 키워드 "const"를 사용하여 선언됩니다.

constant.go라는 파일을 만들고 다음 코드를 추가합니다.

package main
import ("fmt")

func main() {
	const b =10
	fmt.Println(b)
	b = 30
	fmt.Println(b)
}

go run Constant.go를 실행하여 결과를 다음과 같이 확인하세요.

.constant.go:7:4: cannot assign to b

For 루프 예제

루프는 조건에 따라 반복적으로 명령문 블록을 실행하는 데 사용됩니다. 대부분의 프로그래밍 언어는 for, while, do while이라는 3가지 유형의 루프를 제공합니다. 그러나 Go 프로그래밍 언어는 for 루프만 지원합니다.

Golang for 루프의 구문은 다음과 같습니다.

for initialisation_expression; evaluation_expression; iteration_expression{
   // one or more statement
}

초기화_표현식은 Golang for 루프에서 처음으로(한 번만) 실행됩니다.

그런 다음 평가 표현식이 평가되고, 그것이 참이면 블록 내부의 코드가 실행됩니다.

iteration_expression id가 실행되고, Evaluation_expression이 다시 평가됩니다. 그것이 사실이라면 명령문 블록이 다시 실행됩니다. 이는 평가 표현식이 거짓이 될 때까지 계속됩니다.

아래 프로그램을 파일에 복사하고 실행하면 1부터 5까지 숫자를 출력하는 Golang for 루프를 볼 수 있습니다.

package main
import "fmt"

func main() {  
var i int
for i = 1; i <= 5; i++ {
fmt.Println(i)
    }
}

출력은

1
2
3
4
5

다른 경우라면

if else는 조건문입니다. 시낙스는

if condition{
// statements_1
}else{
// statements_2
}

여기에서 조건이 평가되고, 그것이 참이면 states_1이 실행되고, 그렇지 않으면 문_2가 실행됩니다.

else 없이 if 문을 사용할 수도 있습니다. if else 문을 연결할 수도 있습니다. 아래 프로그램에서는 if else에 대해 자세히 설명합니다.

아래 프로그램을 실행해 보세요. 숫자 x가 10보다 작은지 확인합니다. 그렇다면 "x is less than 10"을 인쇄합니다.

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x < 10
        fmt.Println("x is less than 10")
    } 
}

여기서 x 값이 10보다 크므로 if 블록 조건 내의 명령문은 실행되지 않습니다.

이제 아래 프로그램을 살펴보세요. 이 Go 프로그래밍 언어 튜토리얼에는 if 평가 실패 시 실행되는 else 블록이 있습니다.

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else {
        //Executes if x >= 10
        fmt.Println("x is greater than or equals 10")
    }
}

이 프로그램은 당신에게 출력을 제공합니다

x is greater than or equals 10

이제 이 Go 튜토리얼에서는 여러 개의 if else 블록(if else 연결)이 있는 프로그램을 볼 수 있습니다. 아래 Go 예시를 실행해 보세요. 숫자가 10보다 작은지, 10-90 사이인지, 90보다 큰지 확인합니다.

package main
import "fmt"

func main() {  
    var x = 100
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else if x >= 10 && x <= 90 {
        //Executes if x >= 10 and x<=90
        fmt.Println("x is between 10 and 90")
    } else {
        //Executes if both above cases fail i.e x>90
        fmt.Println("x is greater than 90")
    }
}

여기서 먼저 if 조건은 x가 10보다 작은지 여부를 확인하고 그렇지 않습니다. 따라서 다음 조건(else if)이 10에서 90 사이인지 확인하는데 역시 거짓입니다. 그런 다음 출력을 제공하는 else 섹션 아래의 블록을 실행합니다.

x is greater than 90

스위치

Switch는 또 다른 조건문입니다. Switch 문은 표현식을 평가하고 그 결과를 사용 가능한 값(케이스) 집합과 비교합니다. 일치하는 항목이 발견되면 해당 일치(케이스)와 관련된 명령문이 실행됩니다. 일치하는 항목이 없으면 아무것도 실행되지 않습니다. 다른 일치 항목이 발견되지 않으면 실행될 기본 사례를 스위치에 추가할 수도 있습니다. 스위치의 구문은 다음과 같습니다.

switch expression {
    case value_1:
        statements_1
    case value_2:
        statements_2
    case value_n:
        statements_n
    default:
        statements_default
    }

여기서 표현식의 값은 각 경우의 값과 비교됩니다. 일치하는 항목이 발견되면 해당 사례와 관련된 명령문이 실행됩니다. 일치하는 항목이 없으면 기본 섹션 아래의 명령문이 실행됩니다.

아래 프로그램을 실행해 보세요

package main
import "fmt"

func main() {  
    a,b := 2,1
    switch a+b {
    case 1:
        fmt.Println("Sum is 1")
    case 2:
        fmt.Println("Sum is 2")
    case 3:
        fmt.Println("Sum is 3")
    default:
        fmt.Println("Printing default")
    }
}

다음과 같이 출력을 얻을 수 있습니다.

Sum is 3		

a와 b의 값을 3으로 변경하면 결과는 다음과 같습니다.

Printing default

쉼표로 구분하여 한 케이스에 여러 값을 가질 수도 있습니다.

배열

배열은 동일한 유형의 요소 순서로 명명된 고정된 크기를 나타냅니다. 정수와 문자를 모두 포함하는 배열을 가질 수 없습니다. 크기를 정의한 후에는 배열의 크기를 변경할 수 없습니다.

배열을 선언하는 구문은 다음과 같습니다.

var arrayname [size] type

각 배열 요소에는 구문을 사용하여 값을 할당할 수 있습니다.

arrayname [index] = value

배열 인덱스는 다음에서 시작됩니다. 0~크기-1.

다음 구문을 사용하여 선언하는 동안 배열 요소에 값을 할당할 수 있습니다.

arrayname := [size] type {value_0,value_1,…,value_size-1} 

크기를 다음으로 대체하여 값으로 배열을 선언하는 동안 크기 매개변수를 무시할 수도 있습니다. ... 컴파일러는 값의 개수에서 길이를 찾습니다. 구문은

arrayname :=  […] type {value_0,value_1,…,value_size-1}

구문을 사용하여 배열의 길이를 찾을 수 있습니다

len(arrayname)

배열을 이해하려면 아래 Go 예제를 실행하세요.

package main
import "fmt"

func main() {  
    var numbers [3] string //Declaring a string array of size 3 and adding elements 
    numbers[0] = "One"
    numbers[1] = "Two"
    numbers[2] = "Three"
    fmt.Println(numbers[1]) //prints Two
    fmt.Println(len(numbers)) //prints 3
    fmt.Println(numbers) // prints [One Two Three]

    directions := [...] int {1,2,3,4,5} // creating an integer array and the size of the array is defined by the number of elements 
    fmt.Println(directions) //prints [1 2 3 4 5]
    fmt.Println(len(directions)) //prints 5

    //Executing the below commented statement prints invalid array index 5 (out of bounds for 5-element array)
    //fmt.Println(directions[5]) 
}

산출

Two
3
[One Two Three]
[1 2 3 4 5]
5

Golang 슬라이스 및 추가 기능

슬라이스는 배열의 일부 또는 세그먼트입니다. 또는 그것이 가리키는 기본 배열의 보기 또는 부분 보기입니다. 배열에서와 마찬가지로 슬라이스 이름과 인덱스 번호를 사용하여 슬라이스 요소에 액세스할 수 있습니다. 배열의 길이는 변경할 수 없지만 슬라이스의 크기는 변경할 수 있습니다.

슬라이스의 내용은 실제로 배열 요소에 대한 포인터입니다. 그 뜻은 슬라이스의 요소를 변경하면 기본 배열 내용도 영향을 받습니다.

슬라이스를 생성하는 구문은 다음과 같습니다.

var slice_name [] type = array_name[start:end]

그러면 index start부터 end-1까지의 요소가 있는 array_name이라는 배열에서 Slice_name이라는 슬라이스가 생성됩니다.

이제 이 Golang 튜토리얼에서는 아래 프로그램을 실행하겠습니다. 프로그램은 배열에서 슬라이스를 생성하고 이를 인쇄합니다. 또한 슬라이스의 내용을 수정하면 실제 배열도 수정되는 것을 볼 수 있습니다.

package main
import "fmt"

func main() {  
    // declaring array
    a := [5] string {"one", "two", "three", "four", "five"}
    fmt.Println("Array after creation:",a)

    var b [] string = a[1:4] //created a slice named b
    fmt.Println("Slice after creation:",b)

    b[0]="changed" // changed the slice data
    fmt.Println("Slice after modifying:",b)
    fmt.Println("Array after slice modification:",a)
}

결과는 다음과 같이 인쇄됩니다.

Array after creation: [one two three four five]
Slice after creation: [two three four]
Slice after modifying: [changed three four]
Array after slice modification: [one changed three four five]

슬라이스에 적용할 수 있는 Golang len, Golang 추가와 같은 특정 기능이 있습니다.

len(슬라이스_이름) – 슬라이스의 길이를 반환합니다.

추가(슬라이스_이름, 값_1, 값_2) – Golang 추가는 기존 슬라이스에 value_1 및 value_2를 추가하는 데 사용됩니다.

추가(slice_nale1,slice_name2…) – 슬라이스_이름2를 슬라이스_이름1에 추가합니다.

다음 프로그램을 실행하세요.

package main
import "fmt"

func main() {  
	a := [5] string {"1","2","3","4","5"}
	slice_a := a[1:3]
	b := [5] string {"one","two","three","four","five"}
	slice_b := b[1:3]

    fmt.Println("Slice_a:", slice_a)
    fmt.Println("Slice_b:", slice_b)
    fmt.Println("Length of slice_a:", len(slice_a))
    fmt.Println("Length of slice_b:", len(slice_b))

    slice_a = append(slice_a,slice_b...) // appending slice
    fmt.Println("New Slice_a after appending slice_b :", slice_a)
    
    slice_a = append(slice_a,"text1") // appending value
    fmt.Println("New Slice_a after appending text1 :", slice_a)
}

출력은

Slice_a: [2 3]
Slice_b: [two three]
Length of slice_a: 2
Length of slice_b: 2
New Slice_a after appending slice_b : [2 3 two three]
New Slice_a after appending text1 : [2 3 two three text1]

프로그램은 먼저 2개의 슬라이스를 생성하고 그 길이를 인쇄합니다. 그런 다음 한 조각을 다른 조각에 추가한 다음 결과 조각에 문자열을 추가했습니다.

기능

함수는 특정 작업을 수행하는 명령문 블록을 나타냅니다. 함수 선언은 함수 이름, 반환 유형 및 입력 매개변수를 알려줍니다. 함수 정의는 함수에 포함된 코드를 나타냅니다. 함수를 선언하는 구문은 다음과 같습니다.

func function_name(parameter_1 type, parameter_n type) return_type {
//statements
}

매개변수와 반환 유형은 선택 사항입니다. 또한 함수에서 여러 값을 반환할 수도 있습니다.

이제 이 Golang 튜토리얼에서 다음 Golang 예제를 실행해 보겠습니다. 여기서 calc라는 함수는 두 개의 숫자를 받아들이고 덧셈과 뺄셈을 수행하여 두 값을 반환합니다.

package main
import "fmt"

//calc is the function name which accepts two integers num1 and num2
//(int, int) says that the function returns two values, both of integer type.
func calc(num1 int, num2 int)(int, int) {  
    sum := num1 + num2
    diff := num1 - num2
    return sum, diff
}

func main() {  
    x,y := 15,10

    //calls the function calc with x and y an d gets sum, diff as output
    sum, diff := calc(x,y) 
    fmt.Println("Sum",sum)
    fmt.Println("Diff",diff) 
}

출력은

Sum 25
Diff 5

패키지

패키지는 코드를 구성하는 데 사용됩니다. 대규모 프로젝트에서는 단일 파일에 코드를 작성하는 것이 불가능합니다. Go 프로그래밍 언어를 사용하면 코드를 다양한 패키지로 구성할 수 있습니다. 이를 통해 코드 가독성과 재사용성이 향상됩니다. 실행 가능한 Go 프로그램은 main이라는 패키지를 포함해야 하며 프로그램 실행은 main이라는 함수에서 시작됩니다. 다음 구문을 사용하여 프로그램에서 다른 패키지를 가져올 수 있습니다.

import package_name

이 Golang 튜토리얼에서는 다음 Golang 예제에서 패키지를 생성하고 사용하는 방법을 살펴보고 논의하겠습니다.

단계 1) package_example.go라는 파일을 생성하고 아래 코드를 추가하세요.

package main
import "fmt"
//the package to be created
import "calculation"

func main() {  
	x,y := 15,10
	//the package will have function Do_add()
sum := calculation.Do_add(x,y)
fmt.Println("Sum",sum) 
}

위 프로그램에서 fmt는 Go 프로그래밍 언어가 주로 I/O 목적으로 제공하는 패키지입니다. 또한 계산이라는 패키지를 볼 수 있습니다. main() 내부에서 단계 합계 := 계산.Do_add(x,y)를 볼 수 있습니다. 이는 패키지 계산에서 Do_add 함수를 호출한다는 의미입니다.

단계 2) 먼저 이동의 src 폴더 아래 같은 이름의 폴더 안에 패키지 계산을 생성해야 합니다. go가 설치된 경로는 PATH 변수에서 확인할 수 있습니다.

Mac의 경우 echo $PATH를 실행하여 경로를 찾으세요.

따라서 경로는 /usr/local/go입니다.

Windows의 경우 echo %GOROOT%를 실행하여 경로를 찾으세요.

여기서 경로는 C:\Go\입니다.

단계 3) src 폴더로 이동합니다(Mac의 경우 /usr/local/go/src, Windows의 경우 C:\Go\src). 이제 코드에서 패키지 이름은 계산입니다. Go에서는 패키지가 src 디렉토리 아래의 같은 이름의 디렉토리에 있어야 합니다. src 폴더에 계산이라는 이름의 디렉토리를 만듭니다.

단계 4) 계산 디렉터리 내에 calc.go라는 파일을 만들고(이름은 무엇이든 지정할 수 있지만 코드의 패키지 이름이 중요합니다. 여기서는 계산이어야 함) 아래 코드를 추가합니다.

package calculation
  
func Do_add(num1 int, num2 int)(int) {
    sum := num1 + num2
    return sum
}

단계 5) calc.go를 컴파일할 계산 디렉터리에서 go install 명령을 실행합니다.

단계 6) 이제 package_example.go로 돌아가서 go run package_example.go를 실행하세요. 출력은 합계 25가 됩니다.

Do_add 함수의 이름은 대문자로 시작됩니다. Go에서 함수 이름이 대문자로 시작하면 다른 프로그램이 해당 함수에 액세스할 수 없다는 의미이기 때문입니다. 함수 이름이 do_add 라면 오류가 발생했을 것입니다.

내보내지 않은 이름 계산.calc를 참조할 수 없습니다..

연기 및 스태킹 연기

Defer 문은 defer 문을 포함하는 함수가 실행을 완료할 때까지 함수 호출 실행을 연기하는 데 사용됩니다.

예를 들어 이를 알아보겠습니다.

package main
import "fmt"

func sample() {  
    fmt.Println("Inside the sample()")
}
func main() {  
    //sample() will be invoked only after executing the statements of main()
    defer sample()
    fmt.Println("Inside the main()")
}

출력은

Inside the main()
Inside the sample()

여기서는 둘러싸는 함수(main())의 실행이 완료될 때까지 Sample()의 실행이 연기됩니다.

Stacking defer는 여러 defer 문을 사용하고 있습니다. 함수 내에 여러 개의 defer 문이 있다고 가정해 보세요. Go는 지연된 모든 함수 호출을 스택에 배치하고, 둘러싸는 함수가 반환되면 스택된 함수가 스택에서 실행됩니다. 후입선출(LIFO) 순서. 아래 예에서 이를 확인할 수 있습니다.

아래 코드를 실행하세요.

package main
import "fmt"

func display(a int) {  
    fmt.Println(a)
}
func main() {  
    defer display(1)
    defer display(2)
    defer display(3)
    fmt.Println(4)
}

출력은

4
3
2
1			

여기서는 main() 내부의 코드가 먼저 실행된 다음 지연된 함수 호출이 역순으로 실행됩니다(예: 4, 3,2,1).

포인터

포인터를 설명하기 전에 먼저 '&' 연산자에 대해 논의해 보겠습니다. '&' 연산자는 변수의 주소를 얻는 데 사용됩니다. 즉, '&a'는 변수 a의 메모리 주소를 인쇄합니다.

이 Golang 튜토리얼에서는 아래 프로그램을 실행하여 변수의 값과 해당 변수의 주소를 표시합니다.

package main
import "fmt"

func main() {
	a := 20
	fmt.Println("Address:",&a)
	fmt.Println("Value:",a)
}

결과는

Address: 0xc000078008
Value: 20

포인터 변수는 다른 변수의 메모리 주소를 저장합니다. 다음 구문을 사용하여 포인터를 정의할 수 있습니다.

	var variable_name *type

별표(*)는 변수가 포인터임을 나타냅니다. 아래 프로그램을 실행해보면 더 많은 내용을 이해할 수 있을 것입니다.

package main
import "fmt"

func main() {
	//Create an integer variable a with value 20
	a := 20
	
	//Create a pointer variable b and assigned the address of a
	var b *int = &a

	//print address of a(&a) and value of a  
	fmt.Println("Address of a:",&a)
	fmt.Println("Value of a:",a)

	//print b which contains the memory address of a i.e. &a
	fmt.Println("Address of pointer b:",b)

	//*b prints the value in memory address which b contains i.e. the value of a
	fmt.Println("Value of pointer b",*b)

	//increment the value of variable a using the variable b
	*b = *b+1

	//prints the new value using a and *b
	fmt.Println("Value of pointer b",*b)
	fmt.Println("Value of a:",a)}

출력은

Address of a: 0x416020
Value of a: 20
Address of pointer b: 0x416020
Value of pointer b 20
Value of pointer b 21
Value of a: 21

구조

구조는 동일하거나 다른 유형의 요소를 하나 더 포함하는 사용자 정의 데이터 유형입니다.

구조를 사용하는 것은 2단계 프로세스입니다.

먼저 구조체 타입을 생성(선언)합니다.

둘째, 해당 유형의 변수를 만들어 값을 저장합니다.

구조는 관련된 데이터를 함께 저장하고 싶을 때 주로 사용됩니다.

이름, 나이, 주소가 포함된 직원 정보를 생각해 보세요. 이 문제는 2가지 방법으로 처리할 수 있습니다.

3개의 배열을 만듭니다. 하나의 배열은 직원의 이름을 저장하고, 하나는 나이를 저장하고, 세 번째 배열은 나이를 저장합니다.

이름, 주소, 연령의 3개 필드로 구조 유형을 선언합니다. 각 요소가 이름, 주소 및 연령을 갖는 구조 객체인 해당 구조 유형의 배열을 만듭니다.

첫 번째 접근 방식은 효율적이지 않습니다. 이러한 종류의 시나리오에서는 구조가 더 편리합니다.

구조체를 선언하는 구문은 다음과 같습니다.

type structname struct {
   variable_1 variable_1_type
   variable_2 variable_2_type
   variable_n variable_n_type
}

구조 선언의 예는 다음과 같습니다.

type emp struct {
    name string
    address string
    age int
}

여기에 emp라는 새로운 사용자 정의 유형이 생성됩니다. 이제 다음 구문을 사용하여 emp 유형의 변수를 만들 수 있습니다.

	var variable_name struct_name

예입니다

var empdata1 emp 

empdata1의 값을 다음과 같이 설정할 수 있습니다.

empdata1.name = "John"
	empdata1.address = "Street-1, Bangalore"
	empdata1.age = 30

또한 구조 변수를 생성하고 다음과 같이 값을 할당할 수도 있습니다.

empdata2 := emp{"Raj", "Building-1, Delhi", 25}

여기서는 요소의 순서를 유지해야 합니다. Raj는 이름, 다음 요소는 주소, 마지막 요소는 age에 매핑됩니다.

아래 코드를 실행하세요.

package main
import "fmt"

//declared the structure named emp
type emp struct {
        name string
        address string
        age int
}       

//function which accepts variable of emp type and prints name property
func display(e emp) {
          fmt.Println(e.name)
}

func main() {
// declares a variable, empdata1, of the type emp
var empdata1 emp
//assign values to members of empdata1
empdata1.name = "John"
empdata1.address = "Street-1, London"
empdata1.age = 30

//declares and assign values to variable empdata2 of type emp
empdata2 := emp{"Raj", "Building-1, Paris", 25}

//prints the member name of empdata1 and empdata2 using display function
display(empdata1)
display(empdata2)
}

산출

John
Raj

메소드(함수 아님)

메소드는 수신자 인수가 있는 함수입니다. Archi구조적으로는 func 키워드와 메소드 이름 사이에 있습니다. 메소드의 구문은 다음과 같습니다.

func (variable variabletype) methodName(parameter1 paramether1type) {  
}

위의 예제 프로그램을 함수 대신 메서드를 사용하도록 변환해 보겠습니다.

package main
import "fmt"

//declared the structure named emp
type emp struct {
    name string
    address string
    age int
}

//Declaring a function with receiver of the type emp
func(e emp) display() {
    fmt.Println(e.name)
}

func main() {
    //declaring a variable of type emp
    var empdata1 emp
    
    //Assign values to members
    empdata1.name = "John"
    empdata1.address = "Street-1, Lodon"
    empdata1.age = 30

    //declaring a variable of type emp and assign values to members
    empdata2 := emp {
        "Raj", "Building-1, Paris", 25}

    //Invoking the method using the receiver of the type emp
   // syntax is variable.methodname()
    empdata1.display()
    empdata2.display()
}

Go는 객체 지향 언어가 아니며 클래스 개념도 없습니다. 메소드는 objectname.functionname() 구문을 사용하여 클래스의 함수가 호출되는 객체 지향 프로그램에서 수행하는 작업에 대한 느낌을 줍니다.

동시성

Go는 작업의 동시 실행을 지원합니다. 즉, Go는 여러 작업을 동시에 실행할 수 있습니다. 이는 병렬성 개념과는 다릅니다. 병렬성에서는 작업을 작은 하위 작업으로 분할하여 병렬로 실행합니다. 하지만 동시성에서는 여러 작업을 동시에 실행합니다. Go에서는 Goroutine과 Channel을 사용하여 동시성을 구현합니다.

고루틴

고루틴은 다른 기능과 동시에 실행될 수 있는 기능입니다. 일반적으로 함수가 호출되면 제어가 호출된 함수로 전송되고, 일단 실행 제어가 완료되면 호출 함수로 반환됩니다. 그런 다음 호출 함수는 계속해서 실행됩니다. 호출 함수는 나머지 명령문을 진행하기 전에 호출된 함수가 실행을 완료할 때까지 기다립니다.

그러나 고루틴의 경우 호출 함수는 호출된 함수의 실행이 완료될 때까지 기다리지 않습니다. 다음 명령문으로 계속 실행됩니다. 프로그램에는 여러 개의 고루틴이 있을 수 있습니다.

또한, 메인 프로그램은 명령문 실행이 완료되면 종료되며 호출된 고루틴이 완료될 때까지 기다리지 않습니다.

고루틴은 go 키워드와 함수 호출을 사용하여 호출됩니다.

예시

go add(x,y)

아래 Golang 예제를 통해 고루틴을 이해하게 될 것입니다. 아래 프로그램을 실행해 보세요

package main
import "fmt"
    
func display() {
	for i:=0; i<5; i++ {
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	//The main() continues without waiting for display()
	for i:=0; i<5; i++ {
		fmt.Println("In main")
	}
}

출력은

In main
In main
In main
In main
In main

여기서는 고루틴이 시작되기 전에도 메인 프로그램의 실행이 완료되었습니다. display()는 다음 구문을 사용하여 호출되는 고루틴입니다.

go function_name(parameter list)

위 코드에서 main()은 display()가 완료될 때까지 기다리지 않으며, main()은 display()가 코드를 실행하기 전에 실행을 완료했습니다. 따라서 display() 내부의 인쇄 문이 인쇄되지 않았습니다.

이제 우리는 display()의 명령문도 인쇄하도록 프로그램을 수정합니다. main()의 for 루프에 2초의 시간 지연을 추가하고 display()의 for 루프에 1초의 지연을 추가합니다.

package main
import "fmt"
import "time"
    
func display() {
	for i:=0; i<5; i++ {
		time.Sleep(1 * time.Second)
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	for i:=0; i<5; i++ {
		time.Sleep(2 * time.Second)
		fmt.Println("In main")
	}
}

출력은 다음과 다소 유사합니다.

In display
In main
In display
In display
In main
In display
In display
In main
In main
In main

여기에서는 동시 실행으로 인해 두 루프가 겹치는 방식으로 실행되는 것을 볼 수 있습니다.

채널

채널은 기능이 서로 통신하는 방법입니다. 하나의 루틴이 데이터를 배치하고 Golang 서버의 다른 루틴에서 액세스하는 매체로 생각할 수 있습니다.

채널은 다음 구문으로 선언될 수 있습니다.

channel_variable := make(chan datatype)

예:

	ch := make(chan int)

다음 구문을 사용하여 채널에 데이터를 보낼 수 있습니다.

channel_variable <- variable_name

예시

    ch <- x

다음 구문을 사용하여 채널에서 데이터를 수신할 수 있습니다.

    variable_name := <- channel_variable

예시

   y := <- ch

위의 Go 언어 고루틴 예제에서 메인 프로그램이 고루틴을 기다리지 않는 것을 보았습니다. 그러나 채널이 관련된 경우에는 그렇지 않습니다. 고루틴이 데이터를 채널에 푸시하는 경우 main()은 데이터를 얻을 때까지 채널 데이터를 수신하는 명령문을 기다립니다.

아래 Go 언어 예제에서 이를 확인할 수 있습니다. 먼저 일반 고루틴을 작성하고 동작을 살펴보세요. 그런 다음 채널을 사용하도록 프로그램을 수정하고 동작을 확인하십시오.

아래 프로그램을 실행해 보세요

package main
import "fmt"
import "time"
    
func display() {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
}

func main() {
	go display()
	fmt.Println("Inside main()")
}

출력은

Inside main()

main()은 실행을 완료하고 고루틴이 실행되기 전에 종료했습니다. 따라서 display() 내부의 인쇄가 실행되지 않았습니다.

이제 위 프로그램을 수정하여 채널을 사용하고 동작을 확인하세요.

package main
import "fmt"
import "time"
    
func display(ch chan int) {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
	ch <- 1234
}

func main() {
	ch := make(chan int) 
	go display(ch)
	x := <-ch
	fmt.Println("Inside main()")
	fmt.Println("Printing x in main() after taking from channel:",x)
}

출력은

Inside display()
Inside main()
Printing x in main() after taking from channel: 1234

x에 도달하면 main()이 발생합니다. := <-ch는 채널 ch에서 데이터를 기다립니다. display()는 5초 동안 대기한 후 채널 ch에 데이터를 푸시합니다. 채널에서 데이터를 수신할 때 main()이 차단 해제되고 계속 실행됩니다.

채널에 데이터를 푸시하는 발신자는 채널을 닫아 채널에 더 이상 데이터가 추가되지 않음을 수신자에게 알릴 수 있습니다. 이는 루프를 사용하여 데이터를 채널에 푸시할 때 주로 사용됩니다. 다음을 사용하여 채널을 닫을 수 있습니다.

close(channel_name)

그리고 수신 측에서는 다음을 사용하여 채널에서 데이터를 가져오는 동안 추가 변수를 사용하여 채널이 닫혔는지 확인할 수 있습니다.

variable_name, status := <- channel_variable

상태가 True이면 채널에서 데이터를 수신했음을 의미합니다. false인 경우 닫힌 채널에서 읽으려고 한다는 의미입니다.

고루틴 간의 통신을 위해 채널을 사용할 수도 있습니다. 2개의 고루틴을 사용해야 합니다. 하나는 데이터를 채널에 푸시하고 다른 하나는 채널에서 데이터를 수신합니다. 아래 프로그램을 참고하세요

package main
import "fmt"
import "time"

//This subroutine pushes numbers 0 to 9 to the channel and closes the channel
func add_to_channel(ch chan int) {	
	fmt.Println("Send data")
	for i:=0; i<10; i++ {
		ch <- i //pushing data to channel
	}
	close(ch) //closing the channel

}

//This subroutine fetches data from the channel and prints it.
func fetch_from_channel(ch chan int) {
	fmt.Println("Read data")
	for {
		//fetch data from channel
x, flag := <- ch

		//flag is true if data is received from the channel
//flag is false when the channel is closed
if flag == true {
			fmt.Println(x)
		}else{
			fmt.Println("Empty channel")
			break	
		}	
	}
}

func main() {
	//creating a channel variable to transport integer values
	ch := make(chan int)

	//invoking the subroutines to add and fetch from the channel
	//These routines execute simultaneously
	go add_to_channel(ch)
	go fetch_from_channel(ch)

	//delay is to prevent the exiting of main() before goroutines finish
	time.Sleep(5 * time.Second)
	fmt.Println("Inside main()")
}

여기에는 2개의 서브루틴이 있는데 하나는 채널에 데이터를 푸시하고 다른 하나는 채널에 데이터를 인쇄합니다. add_to_channel 함수는 0에서 9까지의 숫자를 더하고 채널을 닫습니다. 동시에 fetch_from_channel 함수는 다음을 기다립니다.

x, flag := <- ch 데이터를 사용할 수 있게 되면 데이터를 인쇄합니다. 플래그가 false이면 종료됩니다. 즉, 채널이 닫혀 있음을 의미합니다.

고루틴이 실행을 마칠 때까지 main()이 종료되는 것을 방지하기 위해 main()의 대기 시간이 제공됩니다.

코드를 실행하고 출력을 다음과 같이 확인하세요.

Read data
Send data
0
1
2
3
4
5
6
7
8
9
Empty channel
Inside main()

클라임웍스와 함께 하늘과 닿는 여정을 시작하세요

Select는 채널에서 작동하는 switch 문으로 볼 수 있습니다. 여기서 case 문은 채널 작업이 됩니다. 일반적으로 각 case 문은 채널에서 읽기 시도됩니다. 케이스 중 하나가 준비되면(채널이 읽힘) 해당 케이스와 관련된 문이 실행됩니다. 여러 케이스가 준비되면 무작위로 하나를 선택합니다. 케이스 중 하나도 준비되지 않은 경우 실행되는 기본 케이스를 가질 수 있습니다.

아래 코드를 보자

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)
    
    //Both case statements wait for data in the chan1 or chan2.
    //chan2 gets data first since the delay is only 2 sec in data2().
    //So the second case will execute and exits the select block
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    }
}

위 프로그램을 실행하면 다음과 같은 결과가 출력됩니다.

from data2()

여기서 select 문은 모든 채널에서 데이터를 사용할 수 있을 때까지 기다립니다. data2()는 두 번째 사례가 실행되도록 하는 2초의 절전 모드 후에 채널에 데이터를 추가합니다.

동일한 프로그램의 선택 항목에 기본 사례를 추가하고 출력을 확인하세요. 여기서 선택 블록에 도달하면 채널에 데이터가 준비된 경우가 없으면 모든 채널에서 데이터를 사용할 수 있을 때까지 기다리지 않고 기본 블록을 실행합니다.

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values  
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)

    //Both case statements check for data in chan1 or chan2.
    //But data is not available (both routines have a delay of 2 and 4 sec)
    //So the default block will be executed without waiting for data in channels.
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    default:
    	fmt.Println("Default case executed")
    }
}

이 프로그램은 다음과 같은 출력을 제공합니다.

Default case executed			

이는 선택 블록에 도달했을 때 읽을 데이터가 있는 채널이 없기 때문입니다. 따라서 default 케이스가 실행됩니다.

뮤텍스

뮤텍스는 상호 배제의 약어입니다. 뮤텍스는 여러 서브루틴이 동시에 리소스에 액세스하는 것을 허용하지 않으려는 경우에 사용됩니다. 뮤텍스에는 Lock과 Unlock이라는 두 가지 메서드가 있습니다. 뮤텍스는 sync 패키지에 포함되어 있습니다. 따라서 sync 패키지를 가져와야 합니다. 상호 배타적으로 실행해야 하는 명령문은 mutex.Lock()과 mutex.Unlock() 내부에 배치할 수 있습니다.

루프가 실행되는 횟수를 세는 예제를 통해 뮤텍스를 배워보겠습니다. 이 프로그램에서는 루틴이 10번 루프를 실행하고 개수가 합계에 저장될 것으로 예상합니다. 이 루틴을 3번 호출하면 총 개수가 30이 됩니다. 개수는 전역 변수 count에 저장됩니다.

먼저, 뮤텍스 없이 프로그램을 실행합니다.

package main
import "fmt"
import "time"
import "strconv"
import "math/rand"
//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

결과보기

 Count after i=1 Count: 11
Count after i=3 Count: 12
Count after i=2 Count: 13
Final Count: 13

실행하면 결과가 달라질 수 있지만 최종 결과는 30이 아닙니다.

여기서 일어나는 일은 3개의 고루틴이 변수 개수에 저장된 루프 개수를 늘리려고 시도하는 것입니다. 현재 카운트가 5이고 goroutine1이 카운트를 6으로 증가시킬 것이라고 가정합니다. 주요 단계는 다음과 같습니다.

임시로 카운트 복사

증분 온도

다시 계산할 수 있도록 온도 저장

goroutine3에 의해 1단계를 수행한 직후에 가정해 보겠습니다. 또 다른 고루틴은 3이 위의 단계를 수행하고 4를 다시 저장한다는 오래된 값을 가질 수 있는데 이는 잘못된 것입니다. 이는 한 루틴이 이미 변수를 사용하고 있을 때 다른 루틴이 기다리게 하는 뮤텍스를 사용하여 방지할 수 있습니다.

이제 뮤텍스를 사용하여 프로그램을 실행하겠습니다. 여기서는 위에서 언급한 3단계가 뮤텍스에서 실행됩니다.

package main
import "fmt"
import "time"
import "sync"
import "strconv"
import "math/rand"

//declare a mutex instance
var mu sync.Mutex

//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		//lock starts here
		mu.Lock()
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
		//lock ends here
		mu.Unlock()
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

이제 출력은 다음과 같습니다.

 Count after i=3 Count: 21
Count after i=2 Count: 28
Count after i=1 Count: 30
Final Count: 30

여기서 우리는 예상 결과를 최종 출력으로 얻습니다. 카운트 읽기, 증가 및 쓰기 명령문이 뮤텍스에서 실행되기 때문입니다.

오류 처리

오류는 열리지 않은 파일 닫기, 존재하지 않는 파일 열기 등과 같은 비정상적인 조건입니다. 함수는 일반적으로 마지막 반환 값으로 오류를 반환합니다.

아래 예에서는 오류에 대해 자세히 설명합니다.

package main
import "fmt"
import "os"

//function accepts a filename and tries to open it.
func fileopen(name string) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        fmt.Println(er)
        return
    }else{
    	fmt.Println("file opened", f.Name())
    }
}

func main() {  
    fileopen("invalid.txt")
}

출력은 다음과 같습니다

open /invalid.txt: no such file or directory

여기서는 존재하지 않는 파일을 열려고 시도했는데 er 변수에 오류가 반환되었습니다. 파일이 유효하면 오류는 null입니다.

맞춤 오류

이 기능을 사용하면 사용자 정의 오류를 생성할 수 있습니다. 이는 오류 패키지의 New()를 사용하여 수행됩니다. 사용자 정의 오류를 활용하기 위해 위 프로그램을 다시 작성하겠습니다.

아래 프로그램을 실행해 보세요

package main
import "fmt"
import "os"
import "errors"

//function accepts a filename and tries to open it.
func fileopen(name string) (string, error) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        //created a new error object and returns it  
        return "", errors.New("Custom error message: File name is wrong")
    }else{
    	return f.Name(),nil
    }
}

func main() {  
    //receives custom error or nil after trying to open the file
    filename, error := fileopen("invalid.txt")
    if error != nil {
        fmt.Println(error)
    }else{
    	fmt.Println("file opened", filename)
    }  
}

출력은 다음과 같습니다

Custom error message:File name is wrong

여기서 Area()는 정사각형의 면적을 반환합니다. 입력이 1보다 작으면 Area()는 오류 메시지를 반환합니다.

파일 읽기

파일은 데이터를 저장하는 데 사용됩니다. Go를 사용하면 파일에서 데이터를 읽을 수 있습니다.

먼저 현재 디렉터리에 아래 내용을 포함하는 data.txt 파일을 만듭니다.

Line one
Line two
Line three

이제 아래 프로그램을 실행하여 전체 파일의 내용이 출력으로 인쇄되는지 확인하세요.

package main
import "fmt"
import "io/ioutil"

func main() {  
    data, err := ioutil.ReadFile("data.txt")
    if err != nil {
        fmt.Println("File reading error", err)
        return
    }
    fmt.Println("Contents of file:", string(data))
}

여기서 데이터 err := ioutil.ReadFile(“data.txt”)는 데이터를 읽고 바이트 시퀀스를 반환합니다. 인쇄하는 동안 문자열 형식으로 변환됩니다.

파일 쓰기

프로그램으로 보면 알겠지만

package main
import "fmt"
import "os"

func main() {  
    f, err := os.Create("file1.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    l, err := f.WriteString("Write Line one")
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(l, "bytes written")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
}

여기에 test.txt라는 파일이 생성됩니다. 파일이 이미 존재하는 경우 파일 내용이 잘립니다. Writeline()은 파일에 내용을 쓰는 데 사용됩니다. 그런 다음 Close()를 사용하여 파일을 닫았습니다.

컨닝 페이퍼

이번 Go 튜토리얼에서는 다음과 같은 내용을 다뤘습니다.

주제 상품 설명 통사론
기본 유형 숫자, 문자열, 부울
변수 변수 선언 및 값 할당 var 변수_이름 유형
var 변수_이름 유형 = 값
var 변수_이름1, 변수_이름2 = 값1, 값2
변수_이름 := 값
상수 한번 할당되면 값을 변경할 수 없는 변수 const 변수 = 값
루프 루프에서 명령문을 실행합니다. 초기화_표현의 경우; 평가_표현; 반복_표현{
// 하나 이상의 명령문
}
다른 경우라면 조건문입니다 if 조건{
// 명령문_1
} 다른 {
// 명령문_2
}
스위치 여러 사례가 포함된 조건문 스위치 표현식 {
사례 값_1:
문_1
사례 값_2:
문_2
케이스 값_n:
문_n
기본값 :
문_기본값
}
배열 동일한 유형의 요소로 구성된 고정 크기 명명된 시퀀스 배열 이름 := [크기] 유형 {value_0,value_1,…,value_size-1}
일부분 배열의 일부 또는 세그먼트 var 슬라이스_이름 [] 유형 = 배열_이름[시작:끝]
기능 특정 작업을 수행하는 명령문 블록 func function_name(parameter_1 유형, 매개변수_n 유형) return_type {
//문장
}
패키지 코드를 구성하는 데 사용됩니다. 코드 가독성 및 재사용성 향상 패키지_이름 가져오기
연기하다 포함된 함수가 실행을 마칠 때까지 함수 실행을 연기합니다. defer function_name(매개변수_목록)
포인터 다른 변수의 메모리 주소를 저장합니다. var 변수_이름 *유형
Structure 자체적으로 동일하거나 다른 유형의 요소를 하나 더 포함하는 사용자 정의 데이터 유형 구조체 이름 구조체 {를 입력하세요.
변수_1 변수_1_유형
변수_2 변수_2_유형
변수_n 변수_n_유형
}
행동 양식 메소드는 수신자 인수가 있는 함수입니다. func(변수 변수 유형) methodName(parameter_list) {
}
고루틴 다른 기능과 동시에 실행할 수 있는 기능입니다. function_name(매개변수_목록)으로 이동
채널 기능이 서로 통신하는 방식입니다. 한 루틴이 데이터를 저장하고 다른 루틴이 액세스하는 매체입니다. 알리다:
ch := make(chan int)
채널로 데이터 보내기:
채널_변수 <- 변수_이름
채널에서 수신:
변수_이름 := <- 채널_변수
클라임웍스와 함께 하늘과 닿는 여정을 시작하세요 채널에서 작동하는 스위치 문. 케이스 문은 채널 작업이 됩니다. 채널 중 하나가 데이터로 준비되면 해당 케이스와 관련된 문이 실행됩니다. 선택하다 {
케이스 x := <-chan1:
fmt.Println(x)
케이스 y := <-chan2:
fmt.Println(y)
}
뮤텍스 Mutex는 여러 서브루틴이 동시에 리소스에 액세스하는 것을 허용하지 않을 때 사용됩니다. Mutex에는 잠금 및 잠금 해제라는 두 가지 방법이 있습니다. 뮤텍스.잠금()
//문장
mutex.Unlock().
파일 읽기 데이터를 읽고 바이트 시퀀스를 반환합니다. 데이터, 오류 := ioutil.ReadFile(파일 이름)
파일 쓰기 파일에 데이터를 씁니다. l, 오류 := f.WriteString(text_to_write)