1. Go で変数を宣言する
Go には変数を宣言するさまざまな方法があり、それぞれが異なるコンテキストに適しています。
1.1.使用する 変数
package main
import "fmt"
func main() {
// Khai báo với type
var name string = "Gopher"
var age int = 15
// Type inference (Go tự suy luận type)
var language = "Go" // string
var version = 1.23 // float64
// Khai báo không gán giá trị (zero value)
var count int // 0
var active bool // false
var message string // ""
var pointer *int // nil
// Khai báo nhiều biến
var (
host string = "localhost"
port int = 8080
debug bool = true
)
fmt.Println(name, age, language, version)
fmt.Println(count, active, message, pointer)
fmt.Println(host, port, debug)
}
1.2.短い宣言 :=
func main() {
// Short declaration - chỉ dùng TRONG function
name := "Gopher" // var name string = "Gopher"
age := 15 // var age int = 15
pi := 3.14159 // var pi float64 = 3.14159
isActive := true // var isActive bool = true
// Khai báo nhiều biến
x, y := 10, 20
host, port := "localhost", 8080
// Swap values
x, y = y, x
fmt.Println(name, age, pi, isActive, x, y, host, port)
}
利用規約: 使用する := 関数内 (短い)。使用する 変数 パッケージ レベル、またはゼロ値が必要な場合。
1.3.定数など イオタ
// Constants - giá trị không đổi
const Pi = 3.14159
const AppName = "MyApp"
// Group constants
const (
MaxRetries = 3
Timeout = 30 // seconds
Version = "1.0.0"
)
// iota - auto-increment cho enums
type Status int
const (
StatusPending Status = iota // 0
StatusActive // 1
StatusInactive // 2
StatusDeleted // 3
)
// iota nâng cao
type Permission int
const (
Read Permission = 1 << iota // 1 (001)
Write // 2 (010)
Execute // 4 (100)
)
// Kết hợp permissions bằng bitwise OR
const ReadWrite = Read | Write // 3 (011)
const All = Read | Write | Execute // 7 (111)
func main() {
fmt.Println(StatusPending) // 0
fmt.Println(StatusActive) // 1
fmt.Println(Read | Write) // 3
fmt.Println(All) // 7
}
2. プリミティブ型
2.1.数値型
| 種類 | サイズ | 範囲 | ゼロ値 |
|---|---|---|---|
int8 | 1バイト | -128 → 127 | 0 |
int16 | 2バイト | -32768 → 32767 | 0 |
int32 / ルーン文字 | 4バイト | -2^31 → 2^31-1 | 0 |
int64 | 8バイト | -2^63 → 2^63-1 | 0 |
整数 | 4または8バイト | プラットフォームに依存する | 0 |
uint8 / バイト | 1バイト | 0→255 | 0 |
uint16 | 2バイト | 0 → 65535 | 0 |
uint32 | 4バイト | 0 → 2^32-1 | 0 |
uint64 | 8バイト | 0 → 2^64-1 | 0 |
float32 | 4バイト | IEEE-754 | 0.0 |
float64 | 8バイト | IEEE-754 | 0.0 |
コンプレックス64 | 8バイト | float32 + float32i | (0+0i) |
コンプレックス128 | 16バイト | float64 + float64i | (0+0i) |
func main() {
// Thường dùng: int, float64
var count int = 42
var price float64 = 19.99
// byte = uint8, thường dùng cho raw data
var b byte = 'A' // 65
// rune = int32, đại diện Unicode code point
var r rune = '🚀' // 128640
// Type conversion - phải explicit
var i int = 42
var f float64 = float64(i) // int → float64
var u uint = uint(f) // float64 → uint
fmt.Println(count, price, b, r, f, u)
}
2.2.文字列
import (
"fmt"
"strings"
)
func main() {
// String là immutable sequence of bytes (UTF-8)
greeting := "Xin chào Go! 🚀"
// String operations
fmt.Println(len(greeting)) // byte length ≠ rune count
fmt.Println([]rune(greeting)) // convert to rune slice
fmt.Println(len([]rune(greeting))) // rune (character) count
// String concatenation
first := "Hello"
last := "World"
full := first + " " + last // simple concatenation
// fmt.Sprintf - formatted string
msg := fmt.Sprintf("Name: %s, Age: %d", "Go", 15)
// strings package
fmt.Println(strings.ToUpper("hello")) // "HELLO"
fmt.Println(strings.Contains("hello", "ell")) // true
fmt.Println(strings.Split("a,b,c", ",")) // ["a", "b", "c"]
fmt.Println(strings.Join([]string{"a", "b"}, "-")) // "a-b"
fmt.Println(strings.TrimSpace(" hello ")) // "hello"
fmt.Println(strings.ReplaceAll("aabb", "a", "x")) // "xxbb"
// Raw string literal (backticks)
query := `SELECT * FROM users
WHERE active = true
ORDER BY created_at DESC`
fmt.Println(full, msg, query)
}
2.3.ブール値
func main() {
var isActive bool = true
var isDeleted bool // zero value: false
// Boolean operators
result := isActive && !isDeleted // AND, NOT
either := isActive || isDeleted // OR
fmt.Println(result, either)
}
3. 複合型
3.1.配列 (固定サイズ)
func main() {
// Array - fixed size, ít dùng trực tiếp
var nums [5]int // [0, 0, 0, 0, 0]
nums[0] = 10
nums[4] = 50
colors := [3]string{"red", "green", "blue"}
// Compiler đếm size
primes := [...]int{2, 3, 5, 7, 11} // size = 5
fmt.Println(nums, colors, primes)
fmt.Println(len(primes)) // 5
}
3.2.スライス (動的配列) - 最も重要です。
func main() {
// Slice - dynamic, dùng nhiều nhất
nums := []int{1, 2, 3, 4, 5}
// make(type, length, capacity)
scores := make([]int, 0, 10) // len=0, cap=10
// Append
scores = append(scores, 95, 87, 92)
fmt.Println(scores) // [95, 87, 92]
fmt.Println(len(scores)) // 3
fmt.Println(cap(scores)) // 10
// Slicing (sub-slice)
first3 := nums[:3] // [1, 2, 3]
last3 := nums[2:] // [3, 4, 5]
middle := nums[1:4] // [2, 3, 4]
// ⚠️ Slices share underlying array!
middle[0] = 99
fmt.Println(nums) // [1, 99, 3, 4, 5] - nums cũng bị thay đổi!
// Copy để tránh shared reference
copied := make([]int, len(nums))
copy(copied, nums)
// Delete element at index 2
nums = append(nums[:2], nums[3:]...)
// slices package (Go 1.21+)
// import "slices"
// slices.Sort(nums)
// slices.Contains(nums, 3)
// slices.Index(nums, 3)
fmt.Println(first3, last3, copied)
}
3.3.マップ(キー-値)
func main() {
// Map literal
ages := map[string]int{
"Alice": 30,
"Bob": 25,
"Carol": 28,
}
// make
scores := make(map[string]float64)
scores["math"] = 9.5
scores["english"] = 8.0
// Access
age := ages["Alice"] // 30
// Check existence (comma-ok idiom)
val, ok := ages["Dave"]
if !ok {
fmt.Println("Dave not found") // val = 0 (zero value)
}
// Delete
delete(ages, "Bob")
// Iterate
for key, value := range ages {
fmt.Printf("%s: %d\n", key, value)
}
// Map size
fmt.Println(len(ages))
fmt.Println(age, val)
}
3.4.構造体
// Struct definition
type User struct {
ID int
Name string
Email string
Age int
IsActive bool
CreatedAt time.Time
}
// Method trên struct
func (u User) FullInfo() string {
return fmt.Sprintf("%s (%s)", u.Name, u.Email)
}
// Pointer receiver - có thể modify struct
func (u *User) Deactivate() {
u.IsActive = false
}
func main() {
// Tạo struct
user1 := User{
ID: 1,
Name: "Alice",
Email: "[email protected]",
Age: 30,
IsActive: true,
}
// Partial initialization
user2 := User{Name: "Bob", Email: "[email protected]"}
// Các field khác = zero value
// Access fields
fmt.Println(user1.Name) // "Alice"
fmt.Println(user1.FullInfo()) // "Alice ([email protected])"
// Pointer to struct
user1.Deactivate()
fmt.Println(user1.IsActive) // false
// Anonymous struct (dùng cho test, temporary)
point := struct {
X, Y int
}{X: 10, Y: 20}
fmt.Println(user2, point)
}
4. ポインタ
func main() {
// Pointer lưu địa chỉ bộ nhớ
x := 42
p := &x // p là *int, trỏ đến x
fmt.Println(x) // 42
fmt.Println(p) // 0xc0000b4008 (địa chỉ)
fmt.Println(*p) // 42 (dereference - lấy giá trị)
*p = 100 // thay đổi giá trị qua pointer
fmt.Println(x) // 100
// new() tạo pointer đến zero value
n := new(int) // *int, giá trị = 0
*n = 42
// Nil pointer
var ptr *string // nil
if ptr == nil {
fmt.Println("ptr is nil")
}
}
// Pass by value vs pass by pointer
func double(x int) {
x *= 2 // Không ảnh hưởng bên ngoài
}
func doublePtr(x *int) {
*x *= 2 // Thay đổi giá trị gốc
}
// Go KHÔNG CÓ pointer arithmetic (an toàn hơn C/C++)
5. ゼロ値
値が割り当てられていない場合、Go のすべての変数はゼロ値で初期化されます。
| 種類 | ゼロ値 |
|---|---|
int、float64、... | 0 |
ブール | 偽 |
文字列.文字列 | 「」 (空の文字列) |
ポインタ、スライス、マップ、関数、インターフェイス、チャネル | なし |
配列。配列 | ゼロ値の配列 |
構造体 | ゼロ値フィールドを含む構造体 |
func main() {
var i int // 0
var f float64 // 0
var b bool // false
var s string // ""
var p *int // nil
var sl []int // nil (nhưng len=0, append vẫn hoạt động)
var m map[string]int // nil (⚠️ KHÔNG thể write, phải make trước)
// ⚠️ Nil map panic khi write
// m["key"] = 1 // panic: assignment to entry in nil map
m = make(map[string]int)
m["key"] = 1 // OK
fmt.Println(i, f, b, s, p, sl, m)
}
6. 制御フロー
6.1. If / Else
func main() {
age := 20
// Standard if-else
if age >= 18 {
fmt.Println("Adult")
} else if age >= 13 {
fmt.Println("Teenager")
} else {
fmt.Println("Child")
}
// If với initialization (Go idiom phổ biến)
if err := doSomething(); err != nil {
fmt.Println("Error:", err)
return
}
// err không tồn tại ở ngoài if scope
// Comma-ok pattern
if val, ok := myMap["key"]; ok {
fmt.Println("Found:", val)
}
}
6.2.スイッチ
func main() {
day := "Monday"
// Switch - không cần break (auto break)
switch day {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
fmt.Println("Weekday")
case "Saturday", "Sunday":
fmt.Println("Weekend")
default:
fmt.Println("Invalid day")
}
// Switch không có expression (thay if-else chain)
score := 85
switch {
case score >= 90:
fmt.Println("A")
case score >= 80:
fmt.Println("B")
case score >= 70:
fmt.Println("C")
default:
fmt.Println("F")
}
// Type switch
var i interface{} = "hello"
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
case bool:
fmt.Printf("Boolean: %t\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
// fallthrough (hiếm dùng)
switch 3 {
case 3:
fmt.Println("3")
fallthrough // tiếp tục case tiếp theo
case 4:
fmt.Println("4")
}
// Output: 3, 4
}
6.3. For ループ
func main() {
// Go CHỈ CÓ for loop (không có while, do-while)
// Classic for
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// While-style
count := 0
for count < 10 {
count++
}
// Infinite loop
// for {
// // break khi cần
// }
// Range over slice
fruits := []string{"apple", "banana", "cherry"}
for index, fruit := range fruits {
fmt.Printf("%d: %s\n", index, fruit)
}
// Chỉ lấy value
for _, fruit := range fruits {
fmt.Println(fruit)
}
// Chỉ lấy index
for i := range fruits {
fmt.Println(i)
}
// Range over map
ages := map[string]int{"Alice": 30, "Bob": 25}
for name, age := range ages {
fmt.Printf("%s is %d\n", name, age)
}
// Range over string (iterates runes)
for i, ch := range "Hello 🌍" {
fmt.Printf("%d: %c (%d)\n", i, ch, ch)
}
// Range over integer (Go 1.22+)
for i := range 5 {
fmt.Println(i) // 0, 1, 2, 3, 4
}
// break, continue, labels
for i := 0; i < 10; i++ {
if i == 3 { continue } // skip 3
if i == 7 { break } // stop at 7
fmt.Println(i)
}
}
7. 型アサーションと変換
func main() {
// Type assertion (cho interface)
var i interface{} = "hello"
// Dangerous (panics nếu sai type)
s := i.(string)
fmt.Println(s) // "hello"
// Safe (comma-ok pattern)
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
}
n, ok := i.(int)
if !ok {
fmt.Println("Not an int") // n = 0
}
// Type conversion (explicit)
var x int = 42
var f float64 = float64(x)
var u uint = uint(f)
// String conversions
import "strconv"
numStr := strconv.Itoa(42) // int → string: "42"
num, err := strconv.Atoi("42") // string → int: 42
flt, err := strconv.ParseFloat("3.14", 64) // string → float64
boolVal, err := strconv.ParseBool("true") // string → bool
fmt.Println(f, u, numStr, num, flt, boolVal, err)
}
8. まとめ
Go にはシンプルですが完全な型システムがあります。覚えておくべき重要な点:
- 使用する
:=ローカル変数の場合、変数パッケージレベルまたはゼロ値の場合 - スライス 配列よりも多く使用され、常に使用されます
追加します。追加する要素を追加するには - 地図 そうだよ
作る書き込み前 (nil マップ → パニック) - ポインタ 値を変更する必要がある場合、または大量のコピーを避ける必要がある場合に使用します。
- ゼロ値 これはコードをより安全にするのに役立つ重要な機能です
- のために 使用される唯一のループです
範囲。範囲繰り返す - 型変換 常に明示的で、暗黙的な変換はありません
次の記事: 関数、インターフェース、エラー処理 — Go プログラミングの 3 つの柱。