ไวยากรณ์พื้นฐาน
ไวยากรณ์พื้นฐานของ 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 เป็นแบบส่วนตัว
package example
// สาธารณะ
const MyName = "jack"
// ส่วนตัว
const mySalary = 20_000กฎการมองเห็นนี้ใช้ได้กับทุกที่ในภาษา Go
การนำเข้า
นำเข้าแพ็กเกจเพื่อใช้ประเภท/เมธอด/ฟังก์ชัน/ตัวแปรในแพ็กเกจนั้น ไวยากรณ์การนำเข้าคือ import ตามด้วยชื่อแพ็กเกจ
package main
import "example"เมื่อนำเข้าหลายแพ็กเกจ คุณสามารถเขียนแบบนี้
package main
import "example"
import "example1"หรือใช้วงเล็บล้อมแบบนี้ วิธีนี้ใช้บ่อยกว่าในทางปฏิบัติ
package main
import (
"example"
"example1"
)หากมีชื่อแพ็กเกจซ้ำกัน หรือชื่อแพ็กเกจซับซ้อนเกินไป คุณสามารถตั้งชื่อแทนให้พวกมันได้
package main
import (
e "example"
e1 "example1"
)เมื่อชื่อแทนเป็นอันเดอร์สกอร์ _ จะเป็นการนำเข้าแบบไม่ระบุชื่อ แพ็กเกจที่นำเข้าแบบไม่ระบุชื่อไม่สามารถใช้งานได้ การทำเช่นนี้มักใช้เพื่อโหลดฟังก์ชัน init ในแพ็กเกจ แต่ไม่ต้องการใช้ประเภทในแพ็กเกจ ตัวอย่างทั่วไปคือการลงทะเบียนไดรเวอร์ฐานข้อมูล แต่คุณไม่จำเป็นต้องใช้ไดรเวอร์ด้วยตนเอง
package main
import (
e "example"
_ "mysql-driver-go"
)หลังจากนำเข้าแล้ว เมื่อต้องการเข้าถึงประเภทในแพ็กเกจ ให้เข้าถึงผ่าน ชื่อแพ็กเกจ.ตัวระบุ เช่นในตัวอย่างด้านล่าง หากคุณพยายามเข้าถึงประเภทส่วนตัว คอมไพเลอร์จะบอกคุณว่าไม่สามารถเข้าถึงได้
package main
import (
"example"
"fmt"
)
func main() {
fmt.Println(example.MyName)
}มีวิธีการนำเข้าพิเศษคือการนำเข้าประเภททั้งหมดในแพ็กเกจนั้นเข้าสู่ขอบเขตแพ็กเกจปัจจุบัน ด้วยวิธีการนำเข้าแบบนี้ ประเภทที่นำเข้าไม่จำเป็นต้องใช้ตัวดำเนินการ . ในการเข้าถึงอีกต่อไป แต่หากมีประเภทชื่อซ้ำจะไม่สามารถผ่านการคอมไพล์ได้
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 รองรับคำอธิบายบรรทัดเดียวและหลายบรรทัด แนะนำให้เว้นวรรคหนึ่งช่องระหว่างคำอธิบายและเนื้อหา เช่น
// นี่คือแพ็กเกจ main
package main
// นำเข้าแพ็กเกจ fmt
import "fmt"
/*
*
นี่คือฟังก์ชันเริ่มต้น main
*/
func main() {
// นี่คือคำสั่ง
fmt.Println("Hello โลก!")
}ตัวระบุ
ตัวระบุคือชื่อหนึ่งชื่อ ใช้สำหรับตั้งชื่อแพ็กเกจ ตั้งชื่อฟังก์ชัน ตั้งชื่อตัวแปร ฯลฯ กฎการตั้งชื่อมีดังนี้
- ประกอบด้วยตัวอักษร ตัวเลข และอันเดอร์สกอร์เท่านั้น
- ขึ้นต้นด้วยตัวอักษรและอันเดอร์สกอร์เท่านั้น
- แยกแยะตัวพิมพ์ใหญ่เล็กอย่างเคร่งครัด
- ไม่สามารถซ้ำกับตัวระบุที่มีอยู่แล้ว นั่นคือมีเอกลักษณ์ในแพ็กเกจ
- ไม่สามารถขัดแย้งกับคีย์เวิร์ดในตัวใดๆ ของ 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 ยังรองรับตัวดำเนินการกำหนดค่าแบบเสริมดังนี้
a += 1
a /= 2
a &^= 2TIP
ภาษา Go ไม่มีตัวดำเนินการเพิ่มค่าและลดค่าด้วยตนเอง พวกมันถูกลดระดับเป็นคำสั่ง statement และกำหนดให้ต้องอยู่หลังตัวถูกดำเนินการเท่านั้น ดังนั้นไม่ต้องสับสนกับปัญหาเช่น i++ และ ++i อีกต่อไป
a++ // ถูกต้อง
++a // ผิด
a-- // ถูกต้องอีกประการหนึ่งคือ พวกมันไม่มีค่าส่งคืนอีกต่อไป ดังนั้นการเขียนคำสั่งเช่น a = b++ จึงผิด
ค่าคงที่ตัวอักษร
ค่าคงที่ตัวอักษร ตามศัพท์ทางวิทยาการคอมพิวเตอร์ หมายถึงสัญลักษณ์ที่ใช้แสดงค่าคงที่ในซอร์สโค้ด หรือเรียกว่าค่าตัวอักษร สองชื่อนี้มีความหมายเหมือนกัน เขียนอะไร ค่าก็คืออะไร ค่าคือค่า "ตามตัวอักษร"
ค่าคงที่ตัวอักษรจำนวนเต็ม
เพื่อให้อ่านง่ายขึ้น อนุญาตให้ใช้เส้นขีดล่าง _ เพื่อแบ่งตัวเลข แต่ใช้ได้เฉพาะ หลังสัญลักษณ์นำหน้า และ ระหว่างตัวเลข เท่านั้น
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ค่าคงที่ตัวอักษรจำนวนจริง
สามารถแสดงจำนวนจริงฐานต่างๆ ได้โดยใช้คำนำหน้าที่ต่างกัน
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)ค่าคงที่ตัวอักษรจำนวนเชิงซ้อน
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 อย่างสมบูรณ์
'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 สัญลักษณ์อัญประกาศคู่ (ใช้ได้เฉพาะในสตริง)ค่าคงที่ตัวอักษรสตริง
ค่าคงที่ตัวอักษรสตริงต้องใช้เครื่องหมายอัญประกาศคู่ "" ล้อมรอบหรือใช้แบ็กควอต ` (สตริงแบ็กควอตไม่อนุญาตให้ใช้อักขระพิเศษ)
`abc` // "abc"
`\n
\n` // "\\n\n\\n"
"\n"
"\"" // `"`
"Hello, world!\n"
"วันนี้สภาพอากาศดี"
"日本語"
"\u65e5本\U00008a9e"
"\xff\u00FF"ฟังก์ชัน
การประกาศฟังก์ชันใน Go ทำผ่านคีย์เวิร์ด func คล้ายกับภาษาส่วนใหญ่
func main() {
println(1)
}แต่ฟังก์ชันใน Go มีสองจุดที่แตกต่าง ประการแรกคือประเภทพารามิเตอร์อยู่ด้านหลัง เช่นนี้
func Hello(name string) {
fmt.Println(name)
}จุดแตกต่างประการที่สองคือการส่งคืนค่าหลายค่า และสามารถมีชื่อได้
func Pos() () (x, y float64) {
...
}สไตล์
เกี่ยวกับส่วนสไตล์การเขียนโค้ด Go บังคับให้ทุกคนใช้สไตล์เดียวกัน Go ทางการมีเครื่องมือจัดรูปแบบ gofmt ซึ่งสามารถใช้ผ่านบรรทัดคำสั่ง เครื่องมือจัดรูปแบบนี้ไม่มีพารามิเตอร์การจัดรูปแบบใดๆ ที่สามารถส่งผ่านได้ มีเพียงสองพารามิเตอร์เท่านั้นที่แสดงกระบวนการจัดรูปแบบ ดังนั้นไม่รองรับการปรับแต่งเลย นั่นหมายความว่าโค้ดที่จัดรูปแบบแล้วด้วยเครื่องมือนี้จะเป็นสไตล์โค้ดแบบเดียวกันทั้งหมด ซึ่งจะลดภาระทางจิตใจของผู้ดูแลระบบอย่างมาก ดังนั้นการแสวงหาความเป็นเอกลักษณ์ในส่วนนี้จึงเป็นทางเลือกที่ไม่ฉลาดนัก
ด้านล่างจะยกตัวอย่างกฎบางข้อ ควรระวังเมื่อเขียนโค้ด
วงเล็บปีกกาของฟังก์ชันขึ้นบรรทัดใหม่
เกี่ยวกับว่าวงเล็บปีกกาหลังฟังก์ชันควรขึ้นบรรทัดใหม่หรือไม่ โปรแกรมเมอร์เกือบทุกคนสามารถให้เหตุผลของตัวเองได้ ใน Go วงเล็บปีกกาทั้งหมดไม่ควรขึ้นบรรทัดใหม่
// ตัวอย่างถูกต้อง
func main() {
fmt.Println("Hello โลก!")
}หากคุณทำเช่นนั้น เช่นนี้
// ตัวอย่างผิด
func main()
{
fmt.Println("Hello โลก!")
}โค้ดแบบนี้ไม่สามารถผ่านการคอมไพล์ได้ ดังนั้น Go จึงบังคับให้วงเล็บปีกกาหลังฟังก์ชันไม่ขึ้นบรรทัดใหม่
การเยื้องโค้ด
Go ใช้ Tab หรือสัญลักษณ์แท็บสำหรับการเยื้องโดยค่าเริ่มต้น ใช้ช่องว่างเฉพาะในบางสถานการณ์พิเศษ
ช่องว่างในโค้ด
ช่องว่างส่วนใหญ่ใน Go มีความหมาย ในบางแง่这也แสดงว่าคอมไพเลอร์มองโค้ดของคุณอย่างไร เช่น การคำนวณทางคณิตศาสตร์ด้านล่าง
2*9 + 1/3*2众所周知 การคูณมีความสำคัญสูงกว่าการบวก หลังการจัดรูปแบบ ช่องว่างระหว่างสัญลักษณ์ * จะดูกระชับมากขึ้น หมายความว่าดำเนินการก่อน ส่วนช่องว่างใกล้สัญลักษณ์ + จะใหญ่กว่า หมายความว่าดำเนินการภายหลัง
การละเว้นวงเล็บปีกกา
ในภาษาอื่น คำสั่ง if และ for มักสามารถเขียนย่อได้ เช่นนี้
for (int i=0; i < 10; i++) printf("%d", i)แต่ใน Go ไม่ได้ คุณสามารถเขียนเพียงบรรทัดเดียว แต่ต้องใส่วงเล็บปีกกา
for i := 0; i < 10; i++ {fmt.Println(i)}นิพจน์สามส่วน
Go ไม่มีนิพจน์สามส่วน ดังนั้นโค้ดด้านล่างไม่สามารถผ่านการคอมไพล์ได้
var c = a > b ? a : bผ่านบทความนี้คุณจะได้รู้จักไวยากรณ์ของ Go เบื้องต้น เนื้อหาต่อไปนี้จะอธิบายอย่างละเอียดมากขึ้น
