https://tour.golang.org/welcome/1
package main
import "fmt"
func main() {
fmt.Println("Hello, 세계")
}
Internal Directories
Code in or below a directory named "internal" is importable only by code in the directory tree rooted at the parent of "internal". Here's an extended version of the directory layout above:
/home/user/go/
src/
crash/
bang/ (go code in package bang)
b.go
foo/ (go code in package foo)
f.go
bar/ (go code in package bar)
x.go
internal/
baz/ (go code in package baz)
z.go
quux/ (go code in package main)
y.go
The code in z.go is imported as "foo/internal/baz", but that import statement can only appear in source files in the subtree rooted at foo. The source files foo/f.go, foo/bar/x.go, and foo/quux/y.go can all import "foo/internal/baz", but the source file crash/bang/b.go cannot.
Packages
모든 Go 프로그램은 패키지로 구성되어 있습니다.
프로그램은 main 패키지에서 실행을 시작합니다.
Imports
This code groups the imports into a parenthesized, "factored" import statement.
package main
import (
"fmt"
"math"
)
func main() {
fmt.Printf("Now you have %g problems.\n", math.Sqrt(7))
}
You can also write multiple import statements, like:
import "fmt"
import "math"
But it is good style to use the factored import statement.
Exported names
In Go, a name is exported if it begins with a capital letter. When importing a package, you can refer only to its exported names. Any "unexported" names are not accessible from outside the package.
Functions
A function can take zero or more arguments.
Notice that the type comes after the variable name.
package main
import "fmt"
// func add(x, y int) int {
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
Multiple results
A function can return any number of results.
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
Named return values
Go's return values may be named. If so, they are treated as variables defined at the top of the function. These names should be used to document the meaning of the return values.
A return statement without arguments returns the named return values. This is known as a "naked" return. 인자가 없는 return 문은 이름이 주어진 반환 값을 반환합니다. 이것을 naked return이라고 합니다.
Naked return statements should be used only in short functions, as with the example shown here. They can harm readability in longer functions.
// 추천 안함. 가독성의 문제가 있을 수 있음.
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
Variables
The var
statement declares a list of variables: as in function argument lists, the type is last. A var
statement can be at package or function level.
package main
import "fmt"
var c, python, java bool
func main() {
var i int
fmt.Println(i, c, python, java)
}
Variables with initializers
A var declaration can include initializers, one per variable.
If an initializer is present, the type can be omitted; the variable will take the type of the initializer.
package main
import "fmt"
var i, j int = 1, 2
func main() {
var c, python, java = true, false, "no!"
fmt.Println(i, j, c, python, java)
}
Short variable declarations
Inside a function, this :=
short assignment statement can be used in place of a var
declaration with implicit type.
Outside a function, every statement begins with a keyword(var,
func
and so on) and so the :=
construct is not available.
package main
import "fmt"
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"
fmt.Println(i, j, k, c, python, java)
}
Basic types
The int
, uint
, and uintptr
types ar usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems. When you need an integer value you should use int
unless you have a specific reason to use a sized or unsigned integer type.
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128
package main
import (
"fmt"
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
func main() {
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
fmt.Printf("Type: %T Value: %v\n", z, z)
}
Zero values
Variables declared without an explicit initial value are given their zero value.
The zero value is:
0
for numeric types,
false
for the boolean type, and
""
(the empty string) for strings.
package main
import "fmt"
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s) // 0 0 false ""
}
Type conversions
The expression T(v) converts the value v to the type T.
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
i := 42
f := float64(i)
u := uint(f)
Type inference
When declaring a variable without specifying an explicit type (either by using the := syntax or var = expression syntax), the variable's type is inferred from the value on the right hand side.
package main
import "fmt"
func main() {
v := 3.14 // change me!
fmt.Printf("v is of type %T\n", v)
}
Constants
Constants are declared like variables, but with the const
keyword. Constants can be character, string, boolean, or numeric values. Constants cannot be using the :=
syntax.
package main
import "fmt"
const Pi = 3.14
func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")
const Truth = true
fmt.Println("Go rules?", Truth)
}
Numeric Constants
Numeric constants are high-precision values. An untyped constant takes the type needed by its context. Try printing needInt(Big)
too. (An int
can store at maximum a 64-bit integer, and sometimes less.)
package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needInt(Small))
fmt.Println(needFloat(Small))
fmt.Println(needFloat(Big))
}
For
Go has only one looping construct, the for
loop.
- the init statement: executed before the first iteration
- the condition expression: evaluated before every iteration
- the post statement: executed at the end of every iteration
the for
statement and the braces { }
are always required.
package main
import "fmt"
func main() {
sum := 0
for i:=0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
The init and post statements are optional.
pakcage main
import "fmt"
func main() {
sum := 1
for ; sum < 1000 ; {
sum += sum;
}
fmt.Println(sum)
}
For is Go's "while"
package main
import "fmt"
func main() {
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
}
infinite loop
package main
import "fmt"
func main() {
for {
}
}
-> timeout running program
If
if
처럼 ()
는 안 써도 되고, {}
는 필수
package main
import (
"fmt"
"math"
)
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
func main() {
fmt.Println(sqrt(2), sqrt(-4))
}
If with a short statement
Like for
the if
statement can start with a short statement to execute before the condition. Variables declared by the statement are only in scope until the end of if
.
package main
import (
"fmt"
"math"
)
func pow(x, n, lim float64) float64 {
if v:= math.Pow(x,n); v < lim {
return v
}
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20)
)
}
If and else
Variables declared inside an if
short statement are also available inside any of the else
blocks.
package main
import (
"fmt"
"math"
)
func pow(x, n, lim float64) float64 {
if v:= math.Pow(x, n); v < lim {
return v
} else {
fmt.Println("%g >= %g\n", v, lim)
}
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20)
)
}
Exercise: Loops and Functions
https://go-tour-ko.appspot.com/flowcontrol/8
Switch
A switch
statement is a shorter way to write a sequence of if - else
statements. It runs the first case whose value is equal to the condition expression.
Go's switch is like the one in C, C++, Java, JavaScript, and PHP, except that Go only runs the selected case, not all the cases that follow. In effect, the break
statement that is needed at the end of each case in those languages is provided automatically in Go. Another important difference is that Go's switch cases need not be constants, and the values involved need not be integers.
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
fmt.Printf("%s. \n", os)
}
}
Switch evaluation order
Switch cases evaluate cases from top to bottom, stopping when a case succeeds.
For example, does not call f
if i==0
.)
switch i {
case 0:
case f():
}
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("When's Saturday?")
today := time.Now().Weekday()
switch time.Saturday {
case today + 0:
fmt.Println("Today.")
case today + 1:
fmt.Println("Tomorrow.")
case today + 2:
fmt.Println("In two days.")
default:
fmt.Println("Too far away.")
}
}
Switch with no condition
Switch without a condition is the same as switch true
. 조건이 없는 Switch는 switch true
와 동일합니다.
This construct can be a clean way to write long if-then-else chains.
pacakge main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
swich {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
Defer
A defer statement defers the execution of a function until the surrounding function returns. defer문은 자신을 둘러싼 함수가 종료할 때까지 어떠한 함수의 실행을 연기합니다.
The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns. 연기된 호출의 인자는 즉시 평가되지만 그 함수 호출은 자신을 둘러싼 함수가 종료할 때까지 수행되지 않습니다.
package main
import "fmt"
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
실행결과
hello
world
Stacking defers
Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order. 연기된 함수 호출들은 스택에 쌓입니다. 한 함수가 종료될 때 그것의 연기된 함수들을 후입선출 순서로 수행됩니다.
package main
import "fmt"
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
실행결과
counting
done
9
8
7
6
5
4
3
2
1
0
Pointers
Go has pointers. A pointer holds the memory address of value. The type *T
is a pointer to a T
value. It's zero value is nil
. Go는 포인터를 지원합니다. 포인터는 값의 메모리 주소를 가지고 있습니다. *T
타입은 T
값을 가리키는 포인터입니다. 이것의 zero value는 nil
입니다.
var p *int
The &
operator generates a pointer to its operand. &
연산자는 이것의 피연산자에 대한 포인터를 생성합니다.
i := 42
p = &i
The *
operator denotes the pointer's underlying value. *
연산자는 포인터가 가리키는 주소의 값을 나타냅니다.
fmt.Println(*p) // read i through the pointer p
*p = 21 // set i through the pointer p
This is known as "dereferencing" or "indirecting". 이것은 "역 참조" 또는 "간접 참조"로 알려져 있습니다.
Unlike C, Go has no pointer arithmetic. C언어와는 다르게, Go는 포인터 산술을 지원하지 않습니다.
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i // point to i
fmt.Println(*p) // read i through the pointer
*p = 21 // set i through the pointer
fmt.Println(i) // see the new value of i
p = &j // pointer to j
*p = *p / 37 // divide j through the pointer
fmt.Println(j) // see the new value of j
}
실행결과
42
21
73
Structs
A struct
is a collection of fields.
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1,2})
}
실행결과
{1 2}
Struct Fields
Struct fields are accessed using a dot.
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
Pointers to structs
Struct fields can be accessed through a struct pointer. 구조체 포인터를 통해서 구조체 필드를 접근할 수 있습니다.
To access the field X
of a struct when we have the struct pointer p
we could write (*p).X
. However, that notation is cumbersome, so the language permits us instead to write just p.X
, without the explicit dereference. (*p).X
로 작성하면, 구조체 포인터 p
에서 구조체의 X
필드에 접근할 수 있습니다. 그러나 위 표기법은 번거로울 수 있습니다. 따라서 이 언어는 역 참조를 명시할 필요 없이 p.X
로 작성할 수 있습니다.
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
fmt.Println(v)
}
Struct Literals
A struct literal denotes a newly allocated struct value by listing the values of its fields. You can list just. a subset of fields by using the Name:
syntax. (And the order of named fields is irrelevant.) 구조체 리터럴은 필드 값을 나열하여 새로 할당된 구조체 값을 나타냅니다. Name:
구문으로 필드의 하위 집합만 나열할 수 있습니다. (명명된 필드의 순서는 무관합니다.)
The special prefix &
returns a pointer to the struct value. 특별한 접두사 &
은 구조체 값으로 포인터를 반환합니다.
package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} //has type *Vertex
)
func main() {
fmt.Println(v1, p, v2, v3)
}
실행 결과
{1 2} &{1 2} {1 0} {0 0}
Array
The type [n]T
is an array of n
values of type T
. [n]T
타입은 타입이 T인 n값들의 배열입니다.
The expression
var a [10]int
declares a variable a
as an array of ten integers.
An array's length is part of its type, so arrays cannot be resized. This seems limiting, but don't worry; Go provides a convenient way of working with arrays.
package main
import "fmt"
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)
primes := [6]int{2,3,5,7,11,13}
fmt.Println(primes)
}
Slices
An array has a fixed size. A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array. 배열은 고정된 크기를 가지고 있습니다. 반면에, 슬라이스는 배역의 요소들을 동적인 크기로, 유연하게 볼 수 있습니다. 실제로, 슬라이스는 배열보다 훨씬 흔합니다.
The type []T
is a slice with elements of type T
.
A slice is formed by specifying two indices, a low and high bound, separated by a colon:
a[low : high]
This selects a half-open range which includes the first elements, but excludes the last one.
The following expression creates a slice which includes elements 1 through 3 of a:
a[1:4]
package main
import "fmt"
func main() {
primees := [6]int{2,3,5,7,11,13}
var s []int = primes[1:4]
fmt.Println(s)
}
실행결과
[3 5 7]
Slices are like references to arrays
A slice does not store any data, it just describes a section of an underlying array. 슬라이스는 어떤 데이터도 저장할 수 없습니다. 이것은 단지 기본 배열의 한 영역을 나타낼 뿐입니다.
Changing the elements of a slice modifies the corresponding elements of its underlying array. 슬라이스의 요소를 변경하면 기본 배열의 해당 요소가 수정됩니다.
Other slices that share the same underlying array will see those changes. 동일한 기본 배열을 공유하는 다른 슬라이스는 이러한 변경사항을 볼 수 있습니다.
package main
import "fmt"
func main() {
names := [4]string(
"John",
"Paul",
"George",
"Ringo"
)
fmt.Println(names)
a := names[0:2]
b := names[1:3]
fmt.Println(a, b)
b[0] = "XXX"
fmt.Println(a, b)
fmt.Println(names)
}
실행 결과
[John Paul George Ringo]
[John Paul] [Paul George]
[John XXX] [XXX George]
[John XXX George Ringo]
Slice literals
A slice literal is like an array literal without the length.
This is an array literal:
[3]bool{true, true, false}
And this creates the same array as above, then builds a slice that references it:
[]bool{true, true, false}
package main
import "fmt"
func main() {
s := []struct{
i int, // 소문자
b bool // 소문자여도 아래에서 접근 가능
}{
{2, true},
{3, false},
{5, true}
}
fmt.Println(s)
}
Slice defaults
When slicing, you may omit the high or low bounds to use their defaults instead.
The default is zero for the low bound and the length of the slice for the high bound.
For the array
var a [10]int
these slice expressions are equivalent:
a[0:10]
a[:10]
a[0:]
a[:]
Slice length and capacity
https://go-tour-ko.appspot.com/moretypes/11
A slice has both a length and capacity.
The length of a slice the number of elements it contains. len(s)
슬라이스의 길이란 슬라이스가 포함하는 요소의 개수입니다.
The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice. cap(s)
슬라이스의 용량이란 슬라이스의 첫 번째 요소부터 계산하는 기본 배열의 요소의 개수입니다.
?? 이해 안감... ?? 뭔말이야
미리 메모리를 잡아놔서 오버헤드를 줄일 수 있음.
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
// 왜 이건 안됨?
s = s[5:]
printSlice(s)
}
실행 결과
len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]
panic: runtime error: slice bounds out of range [5:2]
goroutine 1 [running]:
main.main()
/tmp/sandbox2017825178/prog.go:21 +0xb4
Program exited: status 2.
Q. 왜 [:4]
는 cap가 안 줄어드는데 [2:]
이건 cap가 줄어들까? 그냥 .. 그런건가 ?원래? 흠.?
Nil slices
The zero value of a slice is nil
.
A nil slice has a length and capacity of 0 and has no underlying array.
package main
import "fmt"
func main() {
var s []int
fmt.Println(s, len(s), cap(s))
fmt.Println(s == nil)
}
실행 결과
[] 0 0
true
Creating a slice with make (make 함수로 슬라이스 만들기)
Slices can be created with the built-in make
function; this is how you create dynamically-sized arrays.
The make
function allocates a zeroed array and returns a slice that refers to that array:
make
함수는 0으로 이루어진 배열을 할당합니다. make([]타입, 길이, 용량)
a := make([]int, 5) // len(a)=5
To specify a capacity, pass a third argument to make
:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b - b[1:] // len(b)=4, cap(b)=4
package main
import "fmt"
func main() {
a := make([]int, 5)
printSlice("a", a)
b := make([]int, 0, 5)
printSlice("b", b)
c := b[:2]
printSlice("c", c)
d := c[2:5]
printSlice("d", d)
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %v\n", s, len(x), cap(x), x)
}
Slices of slices
Slices can contain any type, including other slices.
package main
import (
"fmt"
"strings"
)
func main() {
board := [][]string{
[]string("_", "_", "_"},
[]string("_", "_", "_"},
[]string("_", "_", "_"},
}
board[0][0] = "X"
board[2][2] = "0"
for i := 0; i < len(board); i++ {
fmt.Printf("%s\n", strings.Join(board[i], " "))
}
}
Appending to a slice
https://go-tour-ko.appspot.com/moretypes/15
func append(s []T, vs ...T) []T
The first parameter s
of append
is a slice of type T
, and the rest are T
values to append to the slice.
The resulting value of append
is a slice containing all the elements of the original slice plus the provided values.
If the backing array of s
is too small to fit all the given values a bigger array will be allocated. The returned slice will point to the newly allocated array.
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// append works on nil slices.
s = append(s, 0)
printSlice(s)
// The slice grows as needed.
s = append(s, 1)
printSlice(s)
// We can add more than add one element at a time.
s = append(s, 2, 3, 4)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
실행 결과
len=0 cap=0 []
len=1 cap=1 [0]
len=2 cap=2 [0 1]
len=5 cap=6 [0 1 2 3 4] // 왜 cap 이 6이 되었을까?
Range
The range
form of the for
loop iterates over a slice or map.
When raging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index.
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i , v)
}
}
Range continued
You can skip the index or value by assigning to _
.
for i, _ := range pow
for _, value := range pow
if you only want the index, you can omit the second variable.
for i := range pow
Exercise: Slices
'개발~' 카테고리의 다른 글
Postman 사용시 도움이 될 팁 공유 (2) | 2024.10.13 |
---|---|
자주 사용하는 카프카 명령어 (0) | 2021.11.04 |
IntelliJ에서 자주 쓰는 Git 명령어(feat. JIRA) (0) | 2021.05.24 |
vi 편집기 입력 에러 (1) | 2020.05.18 |
Linux alias 설정하기 (0) | 2020.03.20 |