Second Day with Go-Lang
문자열 : Back Quote(``) / 이중인용부호(“”) 를 사용해 표현
- Back Quote ; Raw String Literal
이 안에 있는 문자열은 별도의 해석 없이 Raw String 그대로의 값을 가짐 복수 라인의 문자열을 표현할 때 자주 사용됨
ex) 문자열 안의 \n
은 New Line 으로 해석되지 않음
- 이중인용부호(“”) ; Interpreted String Literal
인용부호 안의 Escape 문자열은 특별한 의미로 해석됨 이중인용부호를 이용해 문자열을 여러 라인에 걸쳐 쓰기 위해 + 연산자 이용
package main
import "fmt"
func main() {
// Raw String Literal. 복수 라인.
rawLiteral := `아리랑\n
아리랑
아라리요`
// Interpreted String Literal
interLiteral := "아리랑아리랑\n아라리요"
// 아래와 같이 +를 사용해 두 라인에 걸쳐 사용할 수 있다.
// interLiteral := "아리랑아리랑\n" + "아라리요"
fmt.Println(rawLiteral)
fmt.Println()
fmt.Println(interLiteral)
}
데이터 타입 변환 (Type Conversion)
아래 예제는 여러 Type Conversion 의 예를 보인 것이다. 한 가지 주의점은 Go 언어에서 타입간 변환은 명시적으로 지정해 주어야 한다. 암묵적 변환이 일어나지 않으므로, 명시적 지정이 없이 변환이 일어나면 런타임 에러가 발생한다.
func main(){
var i int = 100
var u uint = uint(i)
var f float32 = float32(i)
println(f, u)
str := "ABC"
bytes := []bytes(str)
str2 := string(bytes)
println(bytes, str2)
}
Short Variable 선언
함수 블록 내부에서, Short assignment statement(:=
) 가 var
없이 변수 선언을 할 수 있게 한다.
함수 외부에서는 모든 statement 가 keyword(var, func, …) 로 시작해야 하기 때문에 :=
를 사용할 수 없다.
Go 연산자
Go 연산자에서 사용하는 연산자들은 기존의 C++ 연산자들과 유사
- 산술연산자 : 사칙연산(
+, -, *, /
) + Modular 연산(%
), 증감연산자(++, --
) - 관계연산자 :
==, !=, >=, ...
- 논리연산자 :
&&, ||, !
- Bitwise 연산자 :
&, |, ^, <<
- 대입연산자 :
=, *=, >>=, |=
- 포인터연산자 :
&, *
Go 는 포인터 연산자를 제공하지만, 포인터 자체에 더하고 빼는 기능은 제공하지 않음
조건문
-
if 문
Go 의 if 조건문은 조건식을 괄호로 둘러싸지 않아도 된다. 그리고 중괄호를 반드시 if 문과 같은 라인에 두어야 한다. else 문 (else if 문) 은 해당하는 if 문의 중괄호가 끝나는 라인에 같이 존재해야 한다.
if 문에서 조건식을 사용하기 이전에 간단한 문장(Optional Statement) 을 함께 실행할 수 있다. 아래와 같이
val := i * 2
라는 문장을 조건식 이전에 실행할 수 있는데, 이 때 주의할 점은 정의된 변수val
는 블럭 내에서만 사용이 가능하다는 점이다. 이러한 Optional Statement 는 switch, for 문 등 여러 문법에서 사용이 가능하다.
if k == 1 {
println("One")
} else if k == 2 { // 같은 라인
println("Two")
} else { // 같은 라인
println("Other")
}
if val := i * 2; val < max {
println(val)
}
// 아래와 같은 사용은 Scope 를 벗어나서 에러를 발생시킴
val++
-
switch 문
기본적인 사용은 C 언어의 switch 문과 같고, 복수개의 case 값이 있을 경우는 콤마를 써서 해당 값을 나열할 수 있다.
- switch 뒤에 expression 이 없을 수 있다.
- case 문에 Literal 값 뿐이 아니라 expression 을 사용할 수 있다.
- Default fall through 발생하지 않음 ; break 문 없이 다음 case 로 넘어가지 않는다.
- Literal 값 뿐 아니라 Type 에 따라 case 로 분기할 수 있다.
package main
func main(){
var name string
var category = 1
switch category { // 괄호 사용 X
case 1:
name = "Paper Book"
case 2:
name = "eBook"
case 3, 4:
name = "Blog"
default:
name = "Other"
}
println(name)
}
func grade(score int) {
// switch 뒤에 expression 을 적지 않고 case 문에 expression 을 사용해 조건 비교
// 복잡한 if ~ else if ~ else 문을 단순화하는 데 유용하게 사용될 수 있다.
switch {
case score >= 90:
println("A")
case score >= 80:
println("B")
case score >= 70:
println("C")
case score >= 60:
println("D")
default:
println("No Hope")
}
}
switch v.(type) {
case int:
println("int")
case bool:
println("bool")
case string:
println("string")
default:
println("Unknown")
}
package main
func main(){
check(2)
}
func check(val int) {
switch val {
case 1:
println("1 이하")
fallthrough
case 2:
println("2 이하")
fallthrough
case 3:
println("3 이하")
fallthrough
default:
println("default 도달")
}
}
반복문
Go 언어에서 반복문은 for 문 하나만 존재한다.
형식은 for 초기값; 조건식; 증감식 { ... }
의 형식을 따른다.
- for 문 예제
package main
func main(){
sum := 0
for i := 1; i <= 100; i++ { // for 문에서 변수 선언할 때 short assignment (:=) 만 사용 가능
sum += i
}
println(sum)
}
-
조건식만 사용한 for 문
Go 언어에서 for 문은 초기값 / 증감식을 생략할 수 있다. 이를 통해, 다른 언어의 while 문과 유사하게 사용할 수 있도록 한다.
(조건식을 생략할 경우, 무한루프를 생성할 수 있다)
package main
func main(){
n := 1
for n < 100 {
n *= 2
}
println(n)
}
-
for range 문
for range 문은 컬렉션으로부터 한 요소씩 가져와 블록 내의 문장을 실행한다. 다른 언어의 foreach 와 유사한 사용법이다.
for range 문은
for 인덱스, 요소값 := range 컬렉션
과 같이 구성하는데 range 키워드 다음의 컬렉션으로부터 하나씩 요소를 리턴해 그 요소의 인덱스와 값을 for 키워드 다음의 두 변수에 각각 할당한다.
names := []string{"홍길동", "이순신", "강감찬"}
for index, name := range names {
println(index, name)
}
-
break, continue, goto 문
각각 다른 언어에서의 사용과 동일하나 break 를
break Label
과 같이 사용할 수 있다.
package main
func main(){
var a = 1
for a < 15 {
if a == 5 {
a += a
continue
}
a++
if a > 10 {
break
}
}
if a == 11 {
goto END
}
println(a)
END:
println("End")
}
함수
함수는 여러 문장을 묶어 실행하는 코드 블럭의 단위, Go 에서 함수는 func 키워드를 사용해 정의한다. Parameter 는 0개 이상 사용할 수 있고, 각 Parameter 는 이름 뒤에 Parameter Type 을 적어서 정의한다. 함수 Return Type 은 괄호 뒤에 적게 되는데, 이는 다른 언어에서 Return Type 이 함수명 앞에 적힌 것과 대조적이다.
Callee 함수가 반드시 Caller 함수의 앞에 위치해야 할 필요는 없다
package main
func main(){
msg := "Hello"
say(msg)
println(msg)
}
func say(msg string) {
println(msg)
msg = "Changed"
}
-
Parameter 전달 방식
Go 에서 Parameter 를 전달하는 방식은 크게 Pass by Value 와 Pass by Reference 로 나뉜다.
package main
func main() {
msg := "Hello"
say(&msg)
println(msg) // 변경된 메시지 출력
}
func say(msg *string) {
println(*msg)
*msg = "Changed" // 메시지 변경
}
-
Variadic Function (가변 인자 함수)
함수에 고정된 숫자의 Parameter 를 전달하지 않고, 정해지지 않은 개수의 Parameter 를 전달하고자 할 때 가변 Parameter 를 나타내는
...
(3개의 마침표) 를 사용한다. 이 때...
는 함수의 마지막 Parameter 에만 사용될 수 있다. 이렇게 가변 Parameter 를 사용하는 함수를 가변인자 함수라 부른다.
package main
func main() {
say("This", "is", "a", "book")
say("Hi")
}
func say(msg ...string) {
for _, s := range msg {
println(s)
}
}
-
함수 Return Value
Go 언어에서 함수는 Return 이 없을 수도, 하나일 수도, 여러 개일 수도 있다. 또한 Named Return Parameter 라는 기능을 제공하는데, 이는 리턴되는 값들을 Return Parameter 들에 할당할 수 있는 기능이다.
package main
func main() {
total := sum(1, 7, 3, 5, 9)
println(total)
}
func sum(nums ...int) int {
s := 0
for _, n := range nums {
s += n
}
return s
}
Go 에서 여러 Return Value 들을 Return 하기 위해서는 해당 Return Type 들을 괄호 안에 적어 준다.
package main
func main() {
count, total := sum(1, 7, 3, 5, 9)
println(count, total)
}
func sum(nums ...int) (int, int) {
s := 0
count := 0 // s, count := 0, 0 과 같이 표현할 수 있다.
for _, n := range nums {
s += n
count++
}
return count, s
}
Go 에서는 Named Return Parameter 를 사용해서 Return Value 들을 할당해 Return 할 수 있다. 위의 sum() 함수를 Named Return Parameter 를 이용해 고쳐 쓰면 다음과 같다. Return Parameter 의 이름과 그 Type 을 함께 정의해 사용한다. 그리고 함수 내에서는 이 count, total 에 결과값을 직접 할당하고 있음을 볼 수 있다. 함수의 마지막에는 Return 문이 있는데, 실제 return 문에서 아무 값도 Return 하지 않지만 그래도 Return Value 가 있을 경우 빈 return 문을 반드시 써 주어야 한다.
named return parameter 는 기본적으로 0 으로 초기화
func sum(nums ...int) (count int, total int) {
for _, n := range nums {
total += n
}
count = len(nums)
return
}
Go 익명함수
익명함수 (Anonymous Function) ; 함수명을 갖지 않는 함수
일반적으로 익명함수는 그 함수 전체를 변수에 할당하거나 다른 함수의 파라미터에 직접 정의되어 사용된다.
일단 익명함수가 변수에 할당된 이후에는 변수명이 함수명과 같이 취급되며 변수명(Parameters)
형식으로 함수를 호출할 수 있다.
package main
func main() {
sum := func(n ...int) int {
s := 0
for _, i := range n {
s += i
}
return s
}
result := sum(1, 2, 3, 4, 5)
println(result)
}
- 일급함수
Go 언어에서 함수는 일급함수로서 Go 의 기본 타입과 동일하게 취급되며, 다른 함수의 파라미터로 전달하거나 다른 함수의 리턴값으로도 사용될 수 있다. 함수를 다른 함수의 파라미터로 전달하기 위해서는 익명함수를 변수에 할당한 후 이 변수를 전달하는 방법과 직접 다른 함수 호출 파라미터에 함수를 적는 방법이 있다.
package main
func main() {
// 변수 add 에 익명함수 할당
add := func(i int, j int) int {
return i + j
}
// add 함수 전달
r1 := calc(add, 10, 20)
println(r1)
// 직접 첫번째 ㅏ라미터에 익명함수를 정의함
r2 := calc(func(x int, y int) int { return x - y}, 10, 20)
println(r2)
}
func calc(f func(int, int) int, a int, b int) int {
result += f(a, b)
return result
}
- Type 문을 사용한 함수 원형 정의
type 문은 구조체, 인터페이스 등 Custom Type(혹은 User Defined Type) 을 정의하기 위해 사용된다.
위 예제에서 func(x int, y int)
int 함수 원형이 코드 상에 계속 반복되는데, 이 경우 type 문을 정의함으로써 해당 함수의 원형을 간단히 표현할 수 있다.
// 원형 정의
type calculator func(int, int) int
// calculator 원형 사용
func calc(f calculator, a int, b int) int {
result := f(a, b)
return result
}
이렇게 함수의 원형을 정의하고 함수를 다른 Method 에 전달하고 리턴받는 기능을 흔히 Delegate 라 부른다. Go 는 이러한 Delegate 기능을 제공하고 있다.
Reference : 예제로 배우는 Go 프로그래밍