Golang基础概述
首先
此文章是基于在以下Udemy课程中学到的内容所创建的。
https://www.udemy.com/course/golang-webgosql/
如果您想要更详细地学习,建议您亲自参加该课程。
如果您已经参加过该课程,可以将其用于复习等用途。
将数据显示到控制台
使用标准包中的fmt。
Println函数在最后会换行,类似的函数还有Print和Printf。
package main
import "fmt"
func main() {
fmt.Println("Hello World") // コンソールにHello Worldと表示される
}
Go的运行方式
去跑步
只需指定文件即可执行程序的简单方法。
go run ファイル名
go run main.go // 例
去构建
编译文件并创建它。然后可以执行所创建的文件。
go build -o コンパイル後のファイル名 goファイル名
go build -o main main.go // 例
变量
明确的定义
// 形式
var 変数名 型 = 初期値
// 例
var price int = 1000
var name string = "Golang”
可以省略初始值,这种情况下会使用类型的默认初始值。
var price int // int型は0
var name string // string型は空白
暗默的定義
由于可以从初始值进行类型推断,因此不需要进行以下类型指定。
// 形式
変数名 := 初期値
// 例
price := 1000
name := "Golang"
注意点是暗默定义只能在函数内部使用,在函数外部使用将会报错。
:price = 1000 // エラー
func main() {
:name = "Golang" // OK
}
当需要同时定义多个变量时
var (
price int = 1000
name string = "Golang"
)
// or
var price, name = 1000, "Golang"
// or
price, name := 1000, "Golang"
给变量赋值
var price int = 1000
price = 2000 // 代入
fmt.Println(price) // 2000
固定数量
与变量不同,常量无法重新赋值。
const pageCount = 3
const fileName = "filename"
pageCount = 10 // エラー
常量和变量可以一起定义。
const (
pageCount = 3
fileName = "filename"
)
不同类型的样式
整数类型、浮点数类型、逻辑值类型、字符串类型
// 整数型(int)
var i int = 1000
// 浮動小数点型(float)
// 64と32の違いは格納できる値の大きさ
var fl64 float64 = 3.14
var fl32 float32 = 3.14
// 論理値型(bool)
var t bool = true
var f bool = false
// 文字列型(string)
var s string = "Golang"
字节型
// byte型(uint8型)
var b = []byte{97, 98, 99}
fmt.Println(string(b)) // abc
以下链接中的文章对于byte类型很容易理解。
https://qiita.com/s_zaq/items/a6d1df0d1bf79f5bcc2a
数组型
能够存储多个值的数据类型
// 配列型の形式
[要素数]型{値, 値, 値, ...}
var arr1 = [3]int{1, 2, 3}
fmt.Println(arr1) // [1, 2, 3]
// 要素数を...と記載すると初期値の個数になる
var arr2 = [...]int{1, 2, 3} // arr2の型は[3]int
特征是不可变的元素数量,而不同的元素数量被视为不同的类型。
var arr1 = [3]int
var arr2 = [4]int
arri = arr2 // 要素数が異なり型が違うためエラー
切片类型
简而言之,这是一个可以改变数组元素数量的版本,类似于其他编程语言(如js和php)的数组类型。
// スライスの形式
[]型{値, 値, 値, ...} // 配列と違い要素数を指定しない
var s1 = []int{1, 2, 3}
s1 = append(s1, 4) // appendは要素を追加するメソッド
fmt.Println(s1) // [1, 2, 3, 4]
地图类型
// 形式
map[キーの型]値の型{"キー名": 値, ...}
var m = map[string]int{"apple": 100, "banana": 200}
// キーを指定して値を取得
m["apple"] // 100
界面类型
对于每一个值都有相应类型的类型
var x interface{} // {}までが型名
// どの型の値でも代入できる
x = 1
x = 3.14
x = "string"
需要注意的是无法进行计算等操作。
var x interface{} = 2
sum := x + 2 // エラー
类型转换
// float → int
var fl64 float64 = 3.14
int(fl64)
// int → float
var i int = 1
float64(i)
// string → int
var s string = "100"
i, _ = strconv.Atoi(s) // iの型はint
// int → string
var i int = 200
s := strconv.Itoa(i2) // sの型はstring
// string → byte[]
b :=[]byte("abc")
fmt.Println(b) // [97, 98, 99]
// byte[] → string
s := string([]byte{97, 98, 99})
fmt.Println(s) // "abc"
函数 shù)
// 形式
func 関数名(引数 型, ...) 返り値の型 {
// 処理
}
// 例
func Add(x int, y int) int {
return x + y
}
func main() {
i := Add(1, 2)
fmt.Println(i) // 3
}
匿名函数
简单地说,我们可以在函数内部编写代码。
我们可以在函数参数中传递函数。
add := func (x int, y int) int {
return x + y
}
add(1, 2) // 3
最后,您可以在括号内直接添加并执行未命名的函数。
func (x int, y int) int {
return x + y
}(1, 2) // 3
for循环
用于执行重复处理的工具
// 形式
for 初期化; 条件; 繰り返し式 {
// 処理
}
// 例
for i := 0; i < 10; i++ {
fmt.Print(i) // 0123456789
}
在获取索引和值、键和值的方法中,可以使用range。
nums := []int{1, 2, 3}
for index, value := range nums {
fmt.Printf("index: %d, value: %d\n", index, value)
// 出力結果
// index: 0, value: 1
// index: 1, value: 2
// index: 2, value: 3
}
// map
var m = map[string]int{"apple": 100, "banana": 200}
for key, value := range m {
fmt.Printf("key: %s, value: %d\n", key, value)
// 出力結果
// key: apple, value: 100
// key: banana, value: 200
}
延期
通过在代码前面加上defer关键字,可以注册函数在结束时执行的操作。在下面的代码中,可以看到defer语句被首先编写,但实际上是在最后执行的。
func main() {
defer fmt.Println("end")
fmt.Println("start")
// 出力結果
// start
// end
}
有一个使用案例是为了防止打开文件后忘记关闭。如果没有关闭的处理,会导致内存泄漏。
file, _ := os.Create("./test.txt")
// ファイルを開いあとに、defer文を使って閉じる処理をすぐに記述することで、閉じ忘れを防ぐ
defer file.Close()
file.Write([]byte("Test\n"))
并行处理
使用Go语言中的go协程可以轻松编写异步处理。
由于以下情况下的sub方法内有无限循环,导致在调用sub方法后,Main循环无法执行。
func sub() {
for {
fmt.Println("Sub loop")
time.Sleep(100 * time.Millisecond)
}
}
func main() {
sub()
for {
fmt.Println("Main loop")
time.Sleep(200 * time.Millisecond)
}
}
// 出力結果
// Sub loop
// Sub loop
// Sub loop
// ...
通过给`sub`方法的调用添加`go`,将`sub`循环转换为异步处理,可以同时运行两个循环。
func sub() {
for {
fmt.Println("Sub loop")
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go sub() <- ここにgoを追加するだけ
for {
fmt.Println("Main loop")
time.Sleep(200 * time.Millisecond)
}
}
// 出力結果
// Main loop
// Sub loop
// Sub loop
// Main loop
// ...
指针
在内存中指示变量的地址信息
通过这个可以将变量的值共享给其他变量
也就是所谓的传递引用状态。
i := 100
fmt.Println(i) // 100
// 値型のアドレス(&をつける)
fmt.Println(&i) // 0x140000a4008
// ポインタ型(型に*をつけて型指定する)
var p *int = &i // iのアドレスを代入
// ポインタ型のアドレス
fmt.Println(p) // 0x140000a4008
// ポインタ型の実体(*をつける)
fmt.Println(*p) // 100
// iのアドレスをpのポインタ型に代入したため、iとpは同じアドレスを参照している
// このため、iの値を変更するとpの値も変更される。逆も同様
i = 200
fmt.Println(*p) // pも200になる
*p = 300
fmt.Println(i) // iも300になる
通常情况下,函数的参数使用指针类型。
原因是为了可以在函数内部修改通过参数传递的值。
func Double(x int) {
x = x * 2
}
func DoublePoint(x *int) {
*x = *x * 2
}
func main() {
var i int = 100
// iと引数として渡されたi(関数内ではx)は別物のとして扱われる
// このためiの値は変更されない
Double(i)
fmt.Println(i) // 100
// ポインタ型を引数に渡すことで、値を共有するためiの値を変更することができる
DoublePoint(&i)
fmt.Println(i) // 200
}
结构体
在他的言语中,类似于“class”的概念。
// 構造体
type User struct {
Name string
Age int
}
func main() {
// 構造体の定義
var user User = User{Name: "Taro", Age: 20}
fmt.Println(user) // {Taro 20}
// 書き換え
user.Name = "Jiro"
fmt.Println(user) // {Jiro 20}
}
struct 方法
他的言辭中類似於class方法的東西
type User struct {
Name string
Age int
}
// 定義はfuncの後に以下のように(変数名 ストラクト名)を記載すること
func (u *User) UpdateName(name string) {
u.Name = name
}
func main() {
var user User = User{Name: "Taro", Age: 20}
fmt.Println(user) // {Taro 20}
// userから繋げて関数を実行できる
// UpdateName関数内のuはこのuser変数の値になっている
user.UpdateName("Saburo")
fmt.Println(user) // {Saburo 20}
}
使用界面(interface)来通用化(different types)
接口的一般用法
由于下述的User和Admin具有不同的类型,通常情况下无法将它们合并为一起执行相同的操作。
然而,通过使用接口,可以实现以下的功能。
// interfaceの定義
// getName() stringを持つ型はHasName型として扱うことができる
type HasName interface {
getName() string
}
type User struct {
Name string
Age int
}
func (u *User) getName() string {
return u.Name
}
type Admin struct {
Name string
Role int
}
func (u *Admin) getName() string {
return u.Name
}
func main() {
// UserとAdminは本来異なる型だが、両方ともgetName() stringメソッドを持っている
// このためHasNameインターフェイスを用いることで同じ型として扱うことができる
vs := []HasName{
&User{Name: "Taro", Age: 20},
&Admin{Name: "Hanako", Role: 1},
}
for _, v := range vs {
fmt.Println(v.getName())
}
}
从其他文件中使用变量、常量和方法。
通过将名称的首字母改为大写,可以从其他文件中使用。
反之,将名称的首字母改为小写,可以将其设为私有。
var PublicValue int // 他のファイルから使える
var privateValue int
func PublicMethod() { // 他のファイルから使える
}
func privateMethod() {
}
参考文献