Skip to content

ไวยากรณ์พื้นฐาน

ไวยากรณ์พื้นฐานของ Go นั้นง่ายและเข้าใจได้ เรามาเริ่มต้นด้วยตัวอย่างที่ง่ายที่สุด

go
package main

import "fmt"

func main() {
   fmt.Println("Hello โลก!")
}
  • คีย์เวิร์ด package ใช้ประกาศว่าไฟล์ go ปัจจุบันอยู่ในแพ็กเกจใด ไฟล์ entry point ต้องประกาศเป็นแพ็กเกจ main และฟังก์ชัน entry point คือฟังก์ชัน main เมื่อตั้งชื่อแพ็กเกจและฟังก์ชันที่กำหนดเอง ควรหลีกเลี่ยงการซ้ำกับชื่อนี้

  • import เป็นคีย์เวิร์ดสำหรับนำเข้า ตามด้วยชื่อแพ็กเกจที่ต้องการนำเข้า

  • func เป็นคีย์เวิร์ดสำหรับประกาศฟังก์ชัน ใช้สำหรับประกาศฟังก์ชัน

  • fmt.Println("Hello โลก!") เป็นคำสั่งที่เรียกใช้ฟังก์ชัน Println ในแพ็กเกจ fmt เพื่อทำการเอาต์พุต

ข้างต้นเป็นการแนะนำไวยากรณ์อย่างง่าย ต่อไปเราจะมาทำความเข้าใจแนวคิดเหล่านั้นอย่างละเอียดมากขึ้น

แพ็กเกจ

ใน Go โปรแกรมถูกสร้างขึ้นโดยการเชื่อมโยงแพ็กเกจเข้าด้วยกัน หน่วยพื้นฐานที่สุดในการนำเข้าใน Go คือแพ็กเกจ ไม่ใช่ไฟล์ .go แพ็กเกจ其实就是โฟลเดอร์หนึ่ง โฟลเดอร์英文名 package แพ็กเกจจะแชร์ตัวแปร ค่าคงที่ และประเภทที่กำหนดทั้งหมดภายในแพ็กเกจ ชื่อแพ็กเกจแนะนำให้ใช้ตัวอักษรเล็กทั้งหมด และควรสั้นที่สุด

การมองเห็น

ที่กล่าวมาข้างต้นว่าแพ็กเกจแชร์ตัวแปร ค่าคงที่ และประเภทที่กำหนดทั้งหมด แต่สำหรับภายนอกแพ็กเกจแล้วไม่เป็นเช่นนั้น บางครั้งคุณอาจไม่ต้องการให้ผู้อื่นเข้าถึงประเภทใดประเภทหนึ่ง จึงจำเป็นต้องควบคุมการมองเห็น คุณอาจเคยเห็นคีย์เวิร์ดเช่น Public, Private ในภาษา OOP อื่นๆ แต่ในภาษา Go ไม่มีสิ่งเหล่านี้ วิธีการควบคุมการมองเห็นของ Go นั้นง่ายมาก กฎมีดังนี้

  • ชื่อขึ้นต้นด้วยตัวอักษรพิมพ์ใหญ่ คือประเภท/ตัวแปร/ค่าคงที่แบบสาธารณะ
  • ชื่อขึ้นต้นด้วยตัวอักษรเล็กหรืออันเดอร์สกอร์ คือประเภท/ตัวแปร/ค่าคงที่แบบส่วนตัว

เช่นตัวอย่างด้านล่าง ค่าคงที่ MyName เป็นแบบสาธารณะ ส่วนค่าคงที่ mySalary เป็นแบบส่วนตัว

go
package example

// สาธารณะ
const MyName = "jack"

// ส่วนตัว
const mySalary = 20_000

กฎการมองเห็นนี้ใช้ได้กับทุกที่ในภาษา Go

การนำเข้า

นำเข้าแพ็กเกจเพื่อใช้ประเภท/เมธอด/ฟังก์ชัน/ตัวแปรในแพ็กเกจนั้น ไวยากรณ์การนำเข้าคือ import ตามด้วยชื่อแพ็กเกจ

go
package main

import "example"

เมื่อนำเข้าหลายแพ็กเกจ คุณสามารถเขียนแบบนี้

go
package main

import "example"
import "example1"

หรือใช้วงเล็บล้อมแบบนี้ วิธีนี้ใช้บ่อยกว่าในทางปฏิบัติ

go
package main

import (
  "example"
  "example1"
)

หากมีชื่อแพ็กเกจซ้ำกัน หรือชื่อแพ็กเกจซับซ้อนเกินไป คุณสามารถตั้งชื่อแทนให้พวกมันได้

go
package main

import (
  e "example"
  e1 "example1"
)

เมื่อชื่อแทนเป็นอันเดอร์สกอร์ _ จะเป็นการนำเข้าแบบไม่ระบุชื่อ แพ็กเกจที่นำเข้าแบบไม่ระบุชื่อไม่สามารถใช้งานได้ การทำเช่นนี้มักใช้เพื่อโหลดฟังก์ชัน init ในแพ็กเกจ แต่ไม่ต้องการใช้ประเภทในแพ็กเกจ ตัวอย่างทั่วไปคือการลงทะเบียนไดรเวอร์ฐานข้อมูล แต่คุณไม่จำเป็นต้องใช้ไดรเวอร์ด้วยตนเอง

go
package main

import (
  e "example"
  _ "mysql-driver-go"
)

หลังจากนำเข้าแล้ว เมื่อต้องการเข้าถึงประเภทในแพ็กเกจ ให้เข้าถึงผ่าน ชื่อแพ็กเกจ.ตัวระบุ เช่นในตัวอย่างด้านล่าง หากคุณพยายามเข้าถึงประเภทส่วนตัว คอมไพเลอร์จะบอกคุณว่าไม่สามารถเข้าถึงได้

go
package main

import (
  "example"
   "fmt"
)

func main() {
    fmt.Println(example.MyName)
}

มีวิธีการนำเข้าพิเศษคือการนำเข้าประเภททั้งหมดในแพ็กเกจนั้นเข้าสู่ขอบเขตแพ็กเกจปัจจุบัน ด้วยวิธีการนำเข้าแบบนี้ ประเภทที่นำเข้าไม่จำเป็นต้องใช้ตัวดำเนินการ . ในการเข้าถึงอีกต่อไป แต่หากมีประเภทชื่อซ้ำจะไม่สามารถผ่านการคอมไพล์ได้

go
package main

import (
  . "example"
)

WARNING

ใน Go ไม่สามารถนำเข้าแบบวนซ้ำได้ ไม่ว่าจะเป็นทางตรงหรือทางอ้อม เช่น แพ็กเกจ A นำเข้าแพ็กเกจ B แพ็กเกจ B ก็นำเข้าแพ็กเกจ A นี่คือการนำเข้าแบบวนซ้ำทางตรง แพ็กเกจ A นำเข้าแพ็กเกจ C แพ็กเกจ C นำเข้าแพ็กเกจ B แพ็กเกจ B ก็นำเข้าแพ็กเกจ A นี่คือการนำเข้าแบบวนซ้ำทางอ้อม หากมีการนำเข้าแบบวนซ้ำจะไม่สามารถผ่านการคอมไพล์

แพ็กเกจภายใน

ใน Go มีข้อตกลงว่าแพ็กเกจชื่อ internal ในแพ็กเกจหนึ่งเป็นแพ็กเกจภายใน แพ็กเกจภายนอกจะไม่สามารถเข้าถึงเนื้อหาใดๆ ในแพ็กเกจภายใน มิฉะนั้นจะไม่สามารถคอมไพล์ได้ ดูตัวอย่างด้านล่าง

/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

จากโครงสร้างไฟล์จะเห็นว่าแพ็กเกจ crash ไม่สามารถเข้าถึงประเภทในแพ็กเกจ baz ได้

คำอธิบาย

Go รองรับคำอธิบายบรรทัดเดียวและหลายบรรทัด แนะนำให้เว้นวรรคหนึ่งช่องระหว่างคำอธิบายและเนื้อหา เช่น

go
// นี่คือแพ็กเกจ main
package main

// นำเข้าแพ็กเกจ fmt
import "fmt"

/*
*
นี่คือฟังก์ชันเริ่มต้น main
*/
func main() {
  // นี่คือคำสั่ง
  fmt.Println("Hello โลก!")
}

ตัวระบุ

ตัวระบุคือชื่อหนึ่งชื่อ ใช้สำหรับตั้งชื่อแพ็กเกจ ตั้งชื่อฟังก์ชัน ตั้งชื่อตัวแปร ฯลฯ กฎการตั้งชื่อมีดังนี้

  • ประกอบด้วยตัวอักษร ตัวเลข และอันเดอร์สกอร์เท่านั้น
  • ขึ้นต้นด้วยตัวอักษรและอันเดอร์สกอร์เท่านั้น
  • แยกแยะตัวพิมพ์ใหญ่เล็กอย่างเคร่งครัด
  • ไม่สามารถซ้ำกับตัวระบุที่มีอยู่แล้ว นั่นคือมีเอกลักษณ์ในแพ็กเกจ
  • ไม่สามารถขัดแย้งกับคีย์เวิร์ดในตัวใดๆ ของ Go

ด้านล่างแสดงคีย์เวิร์ดในตัวทั้งหมด หรือไปดูรายละเอียดเพิ่มเติมที่ คู่มืออ้างอิง-ตัวระบุ

go
break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

ตัวดำเนินการ

ด้านล่างคือลำดับความสำคัญของสัญลักษณ์ตัวดำเนินการที่รองรับในภาษา Go หรือไปดูรายละเอียดเพิ่มเติมที่ คู่มืออ้างอิง-ตัวดำเนินการ

Precedence    Operator
    5             *  /  %  <<  >>  &  &^
    4             +  -  |  ^
    3             ==  !=  <  <=  >  >=
    2             &&
    1             ||

มีข้อควรระวังเล็กน้อย ในภาษา Go ไม่ได้ใช้ ~ เป็นตัวดำเนินการกลับค่า แต่ใช้สัญลักษณ์ ^ แทน เมื่อใช้ ^ กับตัวเลขสองตัว เช่น a^b มันคือตัวดำเนินการ XOR เมื่อใช้กับตัวเลขตัวเดียว เช่น ^a มันคือตัวดำเนินการกลับค่า Go ยังรองรับตัวดำเนินการกำหนดค่าแบบเสริมดังนี้

go
a += 1
a /= 2
a &^= 2

TIP

ภาษา Go ไม่มีตัวดำเนินการเพิ่มค่าและลดค่าด้วยตนเอง พวกมันถูกลดระดับเป็นคำสั่ง statement และกำหนดให้ต้องอยู่หลังตัวถูกดำเนินการเท่านั้น ดังนั้นไม่ต้องสับสนกับปัญหาเช่น i++ และ ++i อีกต่อไป

a++ // ถูกต้อง
++a // ผิด
a-- // ถูกต้อง

อีกประการหนึ่งคือ พวกมันไม่มีค่าส่งคืนอีกต่อไป ดังนั้นการเขียนคำสั่งเช่น a = b++ จึงผิด

ค่าคงที่ตัวอักษร

ค่าคงที่ตัวอักษร ตามศัพท์ทางวิทยาการคอมพิวเตอร์ หมายถึงสัญลักษณ์ที่ใช้แสดงค่าคงที่ในซอร์สโค้ด หรือเรียกว่าค่าตัวอักษร สองชื่อนี้มีความหมายเหมือนกัน เขียนอะไร ค่าก็คืออะไร ค่าคือค่า "ตามตัวอักษร"

ค่าคงที่ตัวอักษรจำนวนเต็ม

เพื่อให้อ่านง่ายขึ้น อนุญาตให้ใช้เส้นขีดล่าง _ เพื่อแบ่งตัวเลข แต่ใช้ได้เฉพาะ หลังสัญลักษณ์นำหน้า และ ระหว่างตัวเลข เท่านั้น

go
24 // 24
024 // 24
2_4 // 24
0_2_4 // 24
10_000 // 10k
100_000 // 100k
0O24 // 20
0b00 // 0
0x00 // 0
0x0_0 // 0

ค่าคงที่ตัวอักษรจำนวนจริง

สามารถแสดงจำนวนจริงฐานต่างๆ ได้โดยใช้คำนำหน้าที่ต่างกัน

go
0.
72.40
072.40       // == 72.40
2.71828
1.e+0
6.67428e-11
1E6
.25
.12345E+5
1_5.         // == 15.0
0.15e+0_2    // == 15.0

0x1p-2       // == 0.25
0x2.p10      // == 2048.0
0x1.Fp+0     // == 1.9375
0X.8p-0      // == 0.5
0X_1FFFP-16  // == 0.1249847412109375
0x15e-2      // == 0x15e - 2 (integer subtraction)

ค่าคงที่ตัวอักษรจำนวนเชิงซ้อน

go
0i
0123i         // == 123i
0o123i        // == 0o123 * 1i == 83i
0xabci        // == 0xabc * 1i == 2748i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i
0x1p-2i       // == 0x1p-2 * 1i == 0.25i

ค่าคงที่ตัวอักษรอักขระ

ค่าคงที่ตัวอักษรอักขระต้องใช้เครื่องหมายอัญประกาศเดี่ยว '' ล้อมรอบ อักขระใน Go เข้ากันได้กับ utf8 อย่างสมบูรณ์

go
'a'
'ä'
''
'\t'
'\000'
'\007'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'

อักขระพิเศษ

อักขระพิเศษที่ใช้ได้ใน Go

\a   U+0007 สัญลักษณ์กระดิ่ง
\b   U+0008 สัญลักษณ์ถอยหลัง
\f   U+000C สัญลักษณ์ขึ้นหน้าใหม่
\n   U+000A สัญลักษณ์ขึ้นบรรทัดใหม่
\r   U+000D สัญลักษณ์แคร่จ
\t   U+0009 สัญลักษณ์แท็บแนวนอน
\v   U+000B สัญลักษณ์แท็บแนวตั้ง
\\   U+005C สัญลักษณ์แบ็กสแลช
\'   U+0027 สัญลักษณ์อัญประกาศเดี่ยว (ใช้ได้เฉพาะในอักขระ)
\"   U+0022 สัญลักษณ์อัญประกาศคู่ (ใช้ได้เฉพาะในสตริง)

ค่าคงที่ตัวอักษรสตริง

ค่าคงที่ตัวอักษรสตริงต้องใช้เครื่องหมายอัญประกาศคู่ "" ล้อมรอบหรือใช้แบ็กควอต ` (สตริงแบ็กควอตไม่อนุญาตให้ใช้อักขระพิเศษ)

go
`abc`                // "abc"
`\n
\n`                  // "\\n\n\\n"
"\n"
"\""                 // `"`
"Hello, world!\n"
"วันนี้สภาพอากาศดี"
"日本語"
"\u65e5\U00008a9e"
"\xff\u00FF"

ฟังก์ชัน

การประกาศฟังก์ชันใน Go ทำผ่านคีย์เวิร์ด func คล้ายกับภาษาส่วนใหญ่

go
func main() {
  println(1)
}

แต่ฟังก์ชันใน Go มีสองจุดที่แตกต่าง ประการแรกคือประเภทพารามิเตอร์อยู่ด้านหลัง เช่นนี้

func Hello(name string) {
  fmt.Println(name)
}

จุดแตกต่างประการที่สองคือการส่งคืนค่าหลายค่า และสามารถมีชื่อได้

go
func Pos() () (x, y float64) {
    ...
}

สไตล์

เกี่ยวกับส่วนสไตล์การเขียนโค้ด Go บังคับให้ทุกคนใช้สไตล์เดียวกัน Go ทางการมีเครื่องมือจัดรูปแบบ gofmt ซึ่งสามารถใช้ผ่านบรรทัดคำสั่ง เครื่องมือจัดรูปแบบนี้ไม่มีพารามิเตอร์การจัดรูปแบบใดๆ ที่สามารถส่งผ่านได้ มีเพียงสองพารามิเตอร์เท่านั้นที่แสดงกระบวนการจัดรูปแบบ ดังนั้นไม่รองรับการปรับแต่งเลย นั่นหมายความว่าโค้ดที่จัดรูปแบบแล้วด้วยเครื่องมือนี้จะเป็นสไตล์โค้ดแบบเดียวกันทั้งหมด ซึ่งจะลดภาระทางจิตใจของผู้ดูแลระบบอย่างมาก ดังนั้นการแสวงหาความเป็นเอกลักษณ์ในส่วนนี้จึงเป็นทางเลือกที่ไม่ฉลาดนัก

ด้านล่างจะยกตัวอย่างกฎบางข้อ ควรระวังเมื่อเขียนโค้ด

วงเล็บปีกกาของฟังก์ชันขึ้นบรรทัดใหม่

เกี่ยวกับว่าวงเล็บปีกกาหลังฟังก์ชันควรขึ้นบรรทัดใหม่หรือไม่ โปรแกรมเมอร์เกือบทุกคนสามารถให้เหตุผลของตัวเองได้ ใน Go วงเล็บปีกกาทั้งหมดไม่ควรขึ้นบรรทัดใหม่

go
// ตัวอย่างถูกต้อง
func main() {
  fmt.Println("Hello โลก!")
}

หากคุณทำเช่นนั้น เช่นนี้

go
// ตัวอย่างผิด
func main()
{
  fmt.Println("Hello โลก!")
}

โค้ดแบบนี้ไม่สามารถผ่านการคอมไพล์ได้ ดังนั้น Go จึงบังคับให้วงเล็บปีกกาหลังฟังก์ชันไม่ขึ้นบรรทัดใหม่

การเยื้องโค้ด

Go ใช้ Tab หรือสัญลักษณ์แท็บสำหรับการเยื้องโดยค่าเริ่มต้น ใช้ช่องว่างเฉพาะในบางสถานการณ์พิเศษ

ช่องว่างในโค้ด

ช่องว่างส่วนใหญ่ใน Go มีความหมาย ในบางแง่这也แสดงว่าคอมไพเลอร์มองโค้ดของคุณอย่างไร เช่น การคำนวณทางคณิตศาสตร์ด้านล่าง

2*9 + 1/3*2

众所周知 การคูณมีความสำคัญสูงกว่าการบวก หลังการจัดรูปแบบ ช่องว่างระหว่างสัญลักษณ์ * จะดูกระชับมากขึ้น หมายความว่าดำเนินการก่อน ส่วนช่องว่างใกล้สัญลักษณ์ + จะใหญ่กว่า หมายความว่าดำเนินการภายหลัง

การละเว้นวงเล็บปีกกา

ในภาษาอื่น คำสั่ง if และ for มักสามารถเขียนย่อได้ เช่นนี้

c
for (int i=0; i < 10; i++) printf("%d", i)

แต่ใน Go ไม่ได้ คุณสามารถเขียนเพียงบรรทัดเดียว แต่ต้องใส่วงเล็บปีกกา

go
for i := 0; i < 10; i++ {fmt.Println(i)}

นิพจน์สามส่วน

Go ไม่มีนิพจน์สามส่วน ดังนั้นโค้ดด้านล่างไม่สามารถผ่านการคอมไพล์ได้

go
var c = a > b ? a : b

ผ่านบทความนี้คุณจะได้รู้จักไวยากรณ์ของ Go เบื้องต้น เนื้อหาต่อไปนี้จะอธิบายอย่างละเอียดมากขึ้น

Golang by www.golangdev.cn edit