
สารบัญ
uniqueการค้นหาเอกสาร Golang ไม่ใช่เรื่องใหญ่ มีแหล่งข้อมูลที่ดีมากมายเพียงเลือกหนึ่งและเริ่มต้นการเรียนรู้ของคุณ ฉันติดตามการเรียนรู้เป็นหลัก - Miek Gieben
หมายเหตุ : ทุกตัวอย่างในเอกสารนี้จะถูกเก็บไว้ในไดเรกทอรีที่มีชื่อตามส่วน ฉันคิดว่าทุกคำสั่งในส่วน X จะถูกดำเนินการ ในไดเรกทอรีตัวอย่าง/X ดังนั้นฉันจึงไม่เขียน PATH เต็มรูปแบบเพื่อไปที่ไฟล์สคริปต์
/* hello_world.go */
package main
import "fmt" // Implements formatted I/O
/* Say Hello-World */
func main () {
fmt . Printf ( "Hello World" )
}go build helloworld.go # Return an executable called helloworld./helloworldgo run helloworld.go /* When you declare a variable it is assigned the "natural" null value for the type */
var a int // a has a value of 0
var s string // s is assigned the zero string, which is ""
a = 26
s = "hello"
/* Declaring & assigning in Go is a two step process, but they may be combined */
a := 26 // In this case the variable type is deduced from the value. A value of 26 indicates an int for example.
b := "hello" // The type should be string
/* Multiple var declarations may also be grouped (import & const also allow this) */
var (
a int
b string
)
/* Multiple variables of the same type ca also be declared on a single line */
var a , b int
a , b := 26 , 9
/* A special name for a variable is _, any value assigned to it is discarded. */
_ , b := 26 , 9 บูลีน : bool
ตัวเลข :
int - มีความยาวที่เหมาะสมสำหรับเครื่องของคุณ (เครื่อง 32 บิต - 32 บิตเครื่อง 64 บิต - 64 บิต)int8 , int16 , int32 , int64 & byte (นามแฝงสำหรับ uint8 ), uint8 , uint16 , uint32 , uint64float32 , float64 /* numerical_types.go */
package main
func main () {
var a int
var b int32
b = a + a // Give an error: cannot use a + a (type int) as type int32 in assignment.
b = b + 5
} ค่าคงที่: ค่าคงที่ถูกสร้างขึ้นในเวลาที่รวบรวมและสามารถเป็นตัวเลข, สตริงหรือบูลีนเท่านั้น คุณสามารถใช้ iota เพื่อระบุค่า
const (
a = iota // First use of iota will yield 0. Whenever iota is used again on a new line its value is incremented with 1, so b has a vaue of 1.
b
)สตริง :
string ใน GO โปรดทราบว่า! ใน Python (ภาษาการเขียนโปรแกรมที่ฉันโปรดปราน) ฉันสามารถใช้ทั้งสองอย่างสำหรับการกำหนดสตริง s1 := "Hello"
c := [] rune ( s ) // Convert s1 to an array of runes
c [ 0 ] := 'M'
s2 := string ( c ) // Create a new string s2 with the alteration
fmt . Printf ( "%s n " , s2 ) Rune : Rune เป็นนามแฝงสำหรับ int32 (ใช้เมื่อคุณวนซ้ำอักขระในสตริง)
ตัวเลขที่ซับซ้อน : complex128 (64 บิตจริงและชิ้นส่วนจินตภาพ) หรือ complex32
ข้อผิดพลาด : Go มีประเภทในตัวเป็นพิเศษสำหรับข้อผิดพลาดเรียกว่า error.var e
GO 1.18 นำการสนับสนุนสำหรับ ประเภททั่วไป การใช้งานทั่วไปที่จัดทำโดย GO 1.18 เป็นไปตามข้อเสนอพารามิเตอร์ประเภทและอนุญาตให้นักพัฒนาเพิ่มพารามิเตอร์ประเภทเสริมในการพิมพ์และการประกาศฟังก์ชั่น Checkout Golang's Genical Tutorial
package main
import "fmt"
type Number interface {
int64 | float64
}
func main () {
// Initialize a map for the integer values
ints := map [ string ] int64 {
"first" : 34 ,
"second" : 12 ,
}
// Initialize a map for the float values
floats := map [ string ] float64 {
"first" : 35.98 ,
"second" : 26.99 ,
}
fmt . Printf ( "Non-Generic Sums: %v and %v n " ,
SumInts ( ints ),
SumFloats ( floats ))
fmt . Printf ( "Generic Sums: %v and %v n " ,
SumIntsOrFloats [ string , int64 ]( ints ),
SumIntsOrFloats [ string , float64 ]( floats ))
fmt . Printf ( "Generic Sums, type parameters inferred: %v and %v n " ,
SumIntsOrFloats ( ints ),
SumIntsOrFloats ( floats ))
fmt . Printf ( "Generic Sums with Constraint: %v and %v n " ,
SumNumbers ( ints ),
SumNumbers ( floats ))
}
// SumInts adds together the values of m.
func SumInts ( m map [ string ] int64 ) int64 {
var s int64
for _ , v := range m {
s += v
}
return s
}
// SumFloats adds together the values of m.
func SumFloats ( m map [ string ] float64 ) float64 {
var s float64
for _ , v := range m {
s += v
}
return s
}
// SumIntsOrFloats sums the values of map m. It supports both floats and integers
// as map values.
func SumIntsOrFloats [ K comparable , V int64 | float64 ]( m map [ K ] V ) V {
var s V
for _ , v := range m {
s += v
}
return s
}
// SumNumbers sums the values of map m. Its supports both integers
// and floats as map values.
func SumNumbers [ K comparable , V Number ]( m map [ K ] V ) V {
var s V
for _ , v := range m {
s += v
}
return s
} Precedence Operator(s)
Highest * / % << >> & &^
`+ -
== != < <= > >=
<-
&&
Lowest ||
& bitwise และ, | bitwise หรือ, ^ bitwise xor, &^ bit ชัดเจนตามลำดับ 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
var , const , package , import ถูกใช้ในส่วนก่อนหน้าfunc ใช้เพื่อประกาศฟังก์ชั่นและวิธีการreturn ใช้เพื่อส่งคืนจากฟังก์ชั่นgo ใช้สำหรับการเกิดพร้อมกันselect ใช้เพื่อเลือกจากประเภทการสื่อสารที่แตกต่างกันinterfacestruct ใช้สำหรับชนิดข้อมูลนามธรรมtype . if x > 0 {
return y
} esle {
return x
}
if err := MagicFunction (); err != nil {
return err
}
// do somethinggoto คุณข้ามไปที่ฉลากซึ่งจะต้องกำหนดภายในฟังก์ชั่นปัจจุบัน /* goto_test */
/* Create a loop */
func gototestfunc () {
i := 0
Here:
fmt . Println ()
i ++
goto Here
}for ลูปมีสามรูปแบบมีเพียงหนึ่งในเซมิโคลอน: for init ; condition ; post { } // aloop using the syntax borrowed from C
for condition { } // a while loop
for { } // a endless loop
sum := 0
for i := 0 ; i < 10 ; i ++ {
sum = sum + i
} for i := 0 ; i < 10 ; i ++ {
if i > 5 {
break
}
fmt . Println ( i )
}
/* With loops within loop you can specify a label after `break` to identify which loop to stop */
J: for j := 0 ; j < 5 ; j ++ {
for i := 0 ; i < 10 ; i ++ {
if i > 5 {
break J
}
fmt . Println ( i )
}
}พิสัย :
range สำหรับลูป มันสามารถวนซ้ำกับชิ้น, อาร์เรย์, สตริง, แผนที่และช่องrange เป็นตัววนซ้ำที่เมื่อเรียกแล้วจะส่งคืนคู่คีย์ค่าต่อไปจาก "สิ่ง" มันจะวนซ้ำ list := [] string { "a" , "b" , "c" , "d" , "e" , "f" }
for k , v := range list {
// do some fancy thing with k & v
}สวิตช์ :
switch ไม่มีนิพจน์มันจะสวิตช์บน trueif-else-if-else เป็น switch /* Convert hexadecimal character to an int value */
switch { // switch without condition = switch true
case '0' <= c && c <= '9' :
return c - '0'
case 'a' <= c && c <= 'f' :
return c - 'a' + 10
case 'A' <= c && c <= 'F' :
return c - 'A' + 10
}
return 0
/* Automatic fall through */
switch i {
case 0 : fallthrough
case 1 :
f ()
default :
g ()
} close new panic complex
delete make recover real
len append print imag
cap copy println
len ใช้เพื่อส่งคืนความยาวของ strrings, แผนที่, ชิ้นและอาร์เรย์copy สำหรับการคัดลอกชิ้น และ append มีไว้สำหรับการเชื่อมต่อชิ้นบทสรุป: รายการ -> อาร์เรย์, ชิ้น dict -> แผนที่
อาร์เรย์ :
[n]<type> var arr [ 10 ] int // The size is part of the type, fixed size
arr [ 0 ] = 42
arr [ 1 ] = 13
fmt . Printf ( "The first element is %s n " , arr [ 0 ])
// Initialize an array to something other than zero, using composite literal
a := [ 3 ] int { 1 , 2 , 3 }
a := [ ... ] int { 1 , 2 , 3 }ชิ้น :
// Init array primes
primes := [ 6 ] int { 2 , 3 , 5 , 7 , 11 , 13 }
// Init slice s
var s [] int = primes [ 1 : 4 ]
fmt . Println ( s ) // Return [3, 5, 7]
/* slice_length_capacity.go */
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 )
}
func printSlice ( s [] int ) {
fmt . Printf ( "len=%d cap=%d %v n " , len ( s ), cap ( s ), s )
} s := make ([] byte , 5 ) len คือจำนวนองค์ประกอบที่อ้างถึงโดยชิ้น
cap คือจำนวนองค์ประกอบในอาร์เรย์พื้นฐาน (เริ่มต้นที่องค์ประกอบที่อ้างถึงโดยตัวชี้ชิ้น)
s = s [ 2 : 4 ]การหั่นไม่ได้คัดลอกข้อมูลของชิ้น มันสร้างชิ้นใหม่ที่ชี้ไปที่อาร์เรย์ดั้งเดิม สิ่งนี้ทำให้การดำเนินการชิ้นมีประสิทธิภาพในการจัดการตัวบ่งชี้อาร์เรย์ ดังนั้นการปรับเปลี่ยนองค์ประกอบ (ไม่ใช่ชิ้นตัวเอง) ของ slice re-slice ปรับเปลี่ยนองค์ประกอบของชิ้นเดิม:
d := [] byte { 'r' , 'o' , 'a' , 'd' }
e := d [ 2 :]
// e = []byte{'a', 'd'}
e [ 1 ] = 'm'
// e = []byte{'a', 'm'}
// d = []byte{'r', 'o', 'a', 'm'}s บาง ๆ ให้สั้นกว่าความจุ เราสามารถเติบโตไปสู่ความสามารถโดยการหั่นอีกครั้ง s = s [: cap ( s )]ชิ้นไม่สามารถเติบโตได้เกินขีดความสามารถ
// Another example
var array [ m ] int
slice := array [: n ]
// len(slice) == n
// cap(slice) == m
// len(array) == cap(array) == mappend และ copy s0 := [] int { 0 , 0 }
s1 := append ( s0 , 2 ) // same type as s0 - int.
// If the original slice isn't big enough to fit the added values,
// append will allocate a new slice that is big enough. So the slice
// returned by append may refer to a different underlaying array than
// the original slices does.
s2 := append ( s1 , 3 , 5 , 7 )
s3 := append ( s2 , s0 ... ) // []int{0, 0, 2, 3, 5, 7, 0, 0} - three dots used after s0 is needed make it clear explicit that you're appending another slice, instead of a single value
var a = [ ... ] int { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 }
var s = make ([] int , 6 )
// copy function copies slice elements from source to a destination
// returns the number of elements it copied
n1 := copy ( s , a [ 0 :]) // n1 = 6; s := []int{0, 1, 2, 3, 4, 5}
n2 := copy ( s , s [ 2 :]) // n2 = 4; s := []int{2, 3, 4, 5, 4, 5}แผนที่ :
map monthdays := map [ string ] int {
"Jan" : 31 , "Feb" : 28 , "Mar" : 31 ,
"Apr" : 30 , "May" : 31 , "Jun" : 30 ,
"Jul" : 31 , "Aug" : 31 , "Sep" : 30 ,
"Oct" : 31 , "Nov" : 30 , "Dec" : 31 , // A trailing comma is required
}
value , key := monthdays [ "Jan" ]make เมื่อประกาศแผนที่เท่านั้น แผนที่คือ ประเภทอ้างอิง แผนที่ ไม่ใช่ ตัวแปรอ้างอิงค่าของมันคือตัวชี้ไปยังโครงสร้าง runtime.hmap // A struct is a type. It's also a collection of fields
// Declaration
type Vertex struct {
X , Y float64
}
// Creating
var v = Vertex { 1 , 2 }
var v = Vertex { X : 1 , Y : 2 } // Creates a struct by defining values with keys
var v = [] Vertex {{ 1 , 2 },{ 5 , 2 },{ 5 , 5 }} // Initialize a slice of structs
// Accessing members
v . X = 4
// You can declare methods on structs. The struct you want to declare the
// method on (the receiving type) comes between the the func keyword and
// the method name. The struct is copied on each method call(!)
func ( v Vertex ) Abs () float64 {
return math . Sqrt ( v . X * v . X + v . Y * v . Y )
}
// Call method
v . Abs ()
// For mutating methods, you need to use a pointer (see below) to the Struct
// as the type. With this, the struct value is not copied for the method call.
func ( v * Vertex ) add ( n float64 ) {
v . X += n
v . Y += n
}map[string]intefaces // ReadWriter implementations must satisfy both Reader and Writer
type ReadWriter interface {
Reader
Writer
}
// Server exposes all the methods that Logger has
type Server struct {
Host string
Port int
* log. Logger
}
// initialize the embedded type the usual way
server := & Server { "localhost" , 80 , log. New ( ... )}
// methods implemented on the embedded struct are passed through
server. Log ( ... ) // calls server.Logger.Log(...)
// the field name of the embedded type is its type name (in this case Logger)
var logger * log. Logger = server. Logger // General Function
type mytype int
func ( p mytype ) funcname ( q , int ) ( r , s int ) { return 0 , 0 }
// p (optional) bind to a specific type called receiver (a function with a receiver is usually called a method)
// q - input parameter
// r,s - return parameters import "fmt"
func main () {
a := func () { // a is defined as an anonymous (nameless) function,
fmt . Println ( "Hello" )
}
a ()
} func printit ( x int ) {
fmt . Println ( "%v n " , x )
}
func callback ( y int , f func ( int )) {
f ( y )
} /* Open a file & perform various writes & reads on it. */
func ReadWrite () bool {
file . Open ( "file" )
// Do your thing
if failureX {
file . Close ()
return false
}
// Repeat a lot of code.
if failureY {
file . Close ()
return false
}
file . Close ()
return true
}
/* Same situation but using defer */
func ReadWrite () bool {
file . Open ( "file" )
defer file . Close () // add file.Close() to the defer list
// Do your thing
if failureX {
return false
}
if failureY {
return false
}
return true
}Defer จะถูกดำเนินการตามลำดับ LIFO for i := 0 ; i < 5 ; i ++ {
defer fmt . Printf ( "%d " , i ) // 4 3 2 1 0
}defer คุณสามารถเปลี่ยนค่าคืนได้โดยมีเงื่อนไขว่าคุณกำลังใช้พารามิเตอร์ผลลัพธ์และฟังก์ชั่นตัวอักษร ( def func(x int) {/*....*/}(5) ) func f () ( ret int )
defer func () { // Initialized with zero
ret ++
}()
return 0 // This will not be the returned value, because of defer. Ths function f will return 1
} func func1 ( arg ... int ) { // the variadic parameter is just a slice.
for _ , n := range arg {
fmt . Printf ( "And the number is: %d n " , n )
}
}pacnic การดำเนินการหยุด F ฟังก์ชั่นรอการตัดบัญชีใด ๆ ใน F จะถูกดำเนินการตามปกติและจากนั้น f จะกลับไปที่ผู้โทร สำหรับผู้โทร F จากนั้นจะทำตัวเหมือนเรียกร้องให้ตื่นตระหนก กระบวนการยังคงดำเนินต่อไปสแต็กจนกว่าฟังก์ชั่นทั้งหมดใน goroutine ปัจจุบันจะกลับมาที่จุดที่โปรแกรมล่ม ความตื่นตระหนกสามารถเริ่มต้นได้โดยการเรียกความตื่นตระหนกโดยตรง พวกเขายังอาจเกิดจากข้อผิดพลาดรันไทม์เช่นการเข้าถึงอาร์เรย์นอกขอบเขต /* defer_panic_recover.go */
package main
import "fmt"
func main () {
f ()
fmt . Println ( "Returned normally from f." )
}
func f () {
defer func () {
if r := recover (); r != nil {
fmt . Println ( "Recovered in f" , r )
}
}()
fmt . Println ( "Calling g." )
g ( 0 )
fmt . Println ( "Returned normally from g." )
}
func g ( i int ) {
if i > 3 {
fmt . Println ( "Panicking!" )
panic ( fmt . Sprintf ( "%v" , i ))
}
defer fmt . Println ( "Defer in g" , i )
fmt . Println ( "Printing in g" , i )
g ( i + 1 )
}
/* Result */
// Calling g.
// Printing in g 0
// Printing in g 1
// Printing in g 2
// Printing in g 3
// Panicking!
// Defer in g 3
// Defer in g 2
// Defer in g 1
// Defer in g 0
// Recovered in f 4
// Returned normally from f. package even
func Even ( i int ) bool { // starts with capital -> exported
return i % 2 == 0
}
func odd ( i int ) bool { // start with lower-case -> private
return i % 2 == 1
}mkdir $GOPATH /src/even
cp even.go $GOPATH /src/even
go build
go installimport "even"import bar "bytes"src/compress/gzip จะถูกนำเข้าเป็น compress/gzip แต่มีชื่อ gzip ไม่ใช่ compress/gzipring.Ring Package (Package container/ring ) โดยปกติจะเรียกว่า NewRing แต่เนื่องจาก Ring เป็นประเภทเดียวที่ส่งออกโดยแพ็คเกจเนื่องจากแพ็คเกจเรียกว่า ring จึงเรียกว่า New ลูกค้าของแพ็คเกจดูว่าเป็น ring.New ใหม่doc.go แยกต่างหากที่เก็บความคิดเห็นของแพ็คเกจเท่านั้น /*
The regexp package implements a simple library for
regular expressions.
The syntax of the regular expressions accepted is:
regexp:
concatenation { '|' concatenation }
*/
package regexpmain คือไฟล์รายการสำหรับการดำเนินการmain ฟังก์ชั่น init เรียกโดย GO เมื่อแพ็คเกจเริ่มต้น ไม่ต้องใช้อาร์กิวเมนต์ใด ๆ & จะไม่คืนค่าใด ๆ ฟังก์ชั่น init ได้รับการประกาศโดยปริยายโดยไป คุณสามารถมีฟังก์ชั่น init หลายรายการในไฟล์หรือแพ็คเกจ คำสั่งของการดำเนินการของฟังก์ชั่น init ในไฟล์จะเป็นไปตามลำดับของการปรากฏตัวของพวกเขาnullgo run * .go
├── Main package is executed
├── All imported packages are initialized
| ├── All imported packages are initialized (recursive definition)
| ├── All global variables are initialized
| └── init functions are called in lexical file name order
└── Main package is initialized
├── All global variables are initialized
└── init functions are called in lexical file name order การติดตั้งแพ็คเกจบุคคลที่สามนั้นไม่มีอะไรนอกจากการโคลนนิ่งรหัสระยะไกลลงในไดเรกทอรี src/<package> ท้องถิ่น น่าเสียดายที่ GO ไม่รองรับเวอร์ชันแพ็คเกจหรือให้แพ็คเกจผู้จัดการ แต่มีข้อเสนอรอ อยู่ที่นี่
testing และ go test package main
func Sum ( x int , y int ) int {
return x + y
}
func main () {
Sum ( 5 , 5 )
}
// Testcase
package main
import "testing"
func TestSum ( t * testing. T ) {
total := Sum ( 5 , 5 )
if total != 10 {
t . Errorf ( "Sum was incorrect, got: %d, want: %d." , total , 10 )
}
} package main
import "testing"
func TestSum ( t * testing. T ) {
tables := [] struct {
x int
y int
n int
}{
{ 1 , 1 , 2 },
{ 1 , 2 , 3 },
{ 2 , 2 , 4 },
{ 5 , 2 , 7 },
}
for _ , table := range tables {
total := Sum ( table . x , table . y )
if total != table . n {
t . Errorf ( "Sum of (%d+%d) was incorrect, got: %d, want: %d." , table . x , table . y , total , table . n )
}
}
}การเปิดตัวการทดสอบ:
go testgo test github.com/username/packageการทดสอบ http:
net/http/httptest ช่วยอำนวยความสะดวกในการทดสอบอัตโนมัติของทั้งเซิร์ฟเวอร์ HTTP และรหัสไคลเอนต์httptest.ResponseRecorder ได้รับการออกแบบมาโดยเฉพาะเพื่อให้ความสามารถในการทดสอบหน่วยสำหรับการใช้วิธี HTTP Handler โดยการตรวจสอบการเปลี่ยนแปลงสถานะของ HTTP.ResponSewriter ในฟังก์ชั่นทดสอบhttptest ให้ httptest.Server ประเภทเพื่อสร้างเซิร์ฟเวอร์โดยทางโปรแกรมเพื่อทดสอบคำขอไคลเอนต์และส่งการตอบกลับจำลองกลับไปยังลูกค้า คำสั่งครอบคลุม: เครื่องมือ go test มีการครอบคลุมรหัสในตัวสำหรับคำสั่ง
$ go test -cover
PASS
coverage: 50.0% of statements
ok github.com/alexellis/golangbasics1 0.009s
# Generate a HTML coverage report.
$ go test -cover -coverprofile=c.out
$ go tool cover -html=c.out -o coverage.htmlมาตรฐานรหัส: จุดประสงค์ของการเปรียบเทียบคือการวัดประสิทธิภาพของรหัส เครื่องมือบรรทัดคำสั่งการทดสอบ GO มาพร้อมกับการสนับสนุนสำหรับการสร้างอัตโนมัติและการวัดตัวชี้วัดมาตรฐาน เช่นเดียวกับการทดสอบหน่วยเครื่องมือทดสอบใช้ฟังก์ชั่นมาตรฐานเพื่อระบุว่าส่วนใดของรหัสที่จะวัด
ใช้เกณฑ์มาตรฐาน
$ > go test -bench=.
PASS
BenchmarkVectorAdd-2 2000000 761 ns/op
BenchmarkVectorSub-2 2000000 788 ns/op
BenchmarkVectorScale-2 5000000 269 ns/op
BenchmarkVectorMag-2 5000000 243 ns/op
BenchmarkVectorUnit-2 3000000 507 ns/op
BenchmarkVectorDotProd-2 3000000 549 ns/op
BenchmarkVectorAngle-2 2000000 659 ns/op
ok github.com/vladimirvivien/learning-go/ch12/vector 14.123sการข้ามฟังก์ชั่นทดสอบ
> go test -bench=. -run=NONE -v
PASS
BenchmarkVectorAdd-2 2000000 791 ns/op
BenchmarkVectorSub-2 2000000 777 ns/op
Code Testing
[ 314 ]
...
BenchmarkVectorAngle-2 2000000 653 ns/op
ok github.com/vladimirvivien/learning-go/ch12/vector 14.069sมาตรฐานเปรียบเทียบ: เพื่อเปรียบเทียบประสิทธิภาพของอัลกอริทึมที่แตกต่างกันซึ่งใช้ฟังก์ชันการทำงานที่คล้ายกัน การออกกำลังกายอัลกอริทึมโดยใช้มาตรฐานประสิทธิภาพจะระบุว่าการใช้งานใดที่อาจคำนวณได้และมีประสิทธิภาพมากขึ้น
การแยกการพึ่งพา: ปัจจัยสำคัญที่กำหนดการทดสอบหน่วยคือการแยกจากการพึ่งพารันไทม์หรือผู้ทำงานร่วมกัน ตรวจสอบการฉีดพึ่งพา
FMT : แพ็คเกจ fmt ใช้รูปแบบ I/O ที่มีฟังก์ชั่นคล้ายคลึงกับ printf & scanf ของ C คำกริยารูปแบบมาจาก C แต่ง่ายกว่า คำกริยาบางคำ (%-ลำดับ) ที่สามารถใช้:
IO : แพ็คเกจให้อินเทอร์เฟซพื้นฐานสำหรับ I/O ดั้งเดิม งานหลักของมันคือการปิดการใช้งานที่มีอยู่เดิมเช่นในแพ็คเกจระบบ os ลงในอินเทอร์เฟซสาธารณะที่ใช้ร่วมกันซึ่งเป็นนามธรรมของฟังก์ชั่นรวมถึงดั้งเดิมที่เกี่ยวข้องอื่น ๆ
BUFIO : แพ็คเกจนี้ใช้ Buffered I/O มันห่อวัตถุ IO.Reader หรือ iO.Writer สร้างวัตถุอื่น (ผู้อ่านหรือนักเขียน) ที่ใช้อินเทอร์เฟซ แต่ให้บัฟเฟอร์และความช่วยเหลือบางอย่างสำหรับ I/O ที่เป็นข้อความ
การเรียงลำดับ : แพ็คเกจเรียงลำดับให้บริการดั้งเดิมสำหรับการเรียงลำดับอาร์เรย์และคอลเลกชันที่ผู้ใช้กำหนด
STRCONV : แพ็คเกจ STRCONV ใช้การแปลงเป็น & จากการแสดงสตริงของชนิดข้อมูลพื้นฐาน
ระบบปฏิบัติการ : แพ็คเกจ OS ให้อินเทอร์เฟซที่ไม่ขึ้นกับแพลตฟอร์มสำหรับฟังก์ชั่นระบบปฏิบัติการ การออกแบบเป็นเหมือน Unix
การซิงค์ : การซิงค์แพ็คเกจมีการซิงโครไนซ์ขั้นพื้นฐานเช่นล็อคการยกเว้นซึ่งกันและกัน
แฟล็ก : แพ็คเกจธงใช้การแยกวิเคราะห์ธงบรรทัดคำสั่ง
การเข้ารหัส/JSON : แพ็คเกจการเข้ารหัส/JSON ใช้การเข้ารหัสและถอดรหัสวัตถุ JSON ตามที่กำหนดไว้ใน RFC 4627
HTML/เทมเพลต : เทมเพลตที่ขับเคลื่อนด้วยข้อมูลสำหรับการสร้างเอาต์พุตข้อความเช่น HTML
NET/HTTP : แพ็คเกจ NET/HTTP ใช้การแยกวิเคราะห์การร้องขอ HTTP ตอบกลับและ URL & ให้บริการ HTTP Server ที่ขยายได้ & ไคลเอนต์ HTTP พื้นฐาน
ไม่ปลอดภัย : แพ็คเกจที่ไม่ปลอดภัยมีการดำเนินการที่ก้าวไปรอบ ๆ ประเภทความปลอดภัยของโปรแกรม GO โดยปกติคุณไม่ต้องการแพ็คเกจนี้ แต่ก็คุ้มค่าที่จะกล่าวถึงว่าโปรแกรม GO ที่ไม่ปลอดภัยนั้นเป็นไปได้
สะท้อน : แพคเกจสะท้อนแสงดำเนินการสะท้อนเวลาทำงานช่วยให้โปรแกรมสามารถจัดการวัตถุที่มีประเภทโดยพลการ การใช้งานทั่วไปคือการใช้ค่าที่มีอินเตอร์เฟสประเภทคงที่ {} & แยกข้อมูลประเภทแบบไดนามิกโดยการเรียกประเภทของการเรียกซึ่งส่งคืนวัตถุด้วยประเภทประเภทอินเตอร์เฟส
OS/EXEC : แพ็คเกจ OS/EXEC เรียกใช้คำสั่งภายนอก
ไปมีพอยน์เตอร์ แต่ไม่ใช่ตัวชี้ทางอาร์ ธ เมติกดังนั้นพวกเขาจึงทำหน้าที่คล้ายกับการอ้างอิงมากกว่าพอยน์เตอร์ที่คุณอาจรู้จาก C
var p * int
p ++thisพอยน์เตอร์มีประโยชน์ โปรดจำไว้ว่าเมื่อคุณเรียกฟังก์ชั่นใน GO ตัวแปรจะ ผ่านค่าผ่าน ดังนั้นเพื่อประสิทธิภาพและความเป็นไปได้ในการปรับเปลี่ยนค่าที่ผ่านในฟังก์ชั่นที่เรามีพอยน์เตอร์
ประเภทตัวชี้ ( * ประเภท) & ที่อยู่ของ (&) ตัวดำเนินการ *: หากตัวแปรได้รับการประกาศ var x int , นิพจน์ &x ("ที่อยู่ของ x") ให้ตัวชี้ไปยังตัวแปรจำนวนเต็ม (ค่าประเภท * int ) หากค่านี้เรียกว่า p เราจะพูดว่า " p ชี้ไปที่ x " หรือเทียบเท่า " p มีที่อยู่ของ x " ตัวแปรที่ p -Points ถูกเขียน *p นิพจน์ *p ให้ค่าของตัวแปรนั้น, int , แต่เนื่องจาก *p หมายถึงตัวแปรจึงอาจปรากฏทางด้านซ้ายมือของการกำหนดซึ่งในกรณีนี้การกำหนดจะอัปเดตตัวแปร อ้างอิงที่นี่
x := 1
p := & x // p, of type *int, points to x
fmt . Println ( * p ) // "1"
* p = 2 // equivalent to x = 2
fmt . Println ( x ) // "2"ตัวแปรที่ประกาศใหม่ทั้งหมดได้รับการกำหนดค่าศูนย์และพอยน์เตอร์ของพวกเขานั้นไม่แตกต่างกัน ตัวชี้ที่ประกาศใหม่หรือเพียงแค่ตัวชี้ที่ชี้ไปที่ไม่มีอะไรไม่มีค่า
var p * int // declare a pointer
fmt . Printf ( "%v" , p )
var i int
p = & i // Make p point to i
fmt . Printf ( "%v" , p ) // Print somthing like 0x7ff96b81c000a // Go program to illustrate the
// concept of the Pointer to Pointer
package main
import "fmt"
// Main Function
func main () {
// taking a variable
// of integer type
var V int = 100
// taking a pointer
// of integer type
var pt1 * int = & V
// taking pointer to
// pointer to pt1
// storing the address
// of pt1 into pt2
var pt2 * * int = & pt1
fmt . Println ( "The Value of Variable V is = " , V )
fmt . Println ( "Address of variable V is = " , & V )
fmt . Println ( "The Value of pt1 is = " , pt1 )
fmt . Println ( "Address of pt1 is = " , & pt1 )
fmt . Println ( "The value of pt2 is = " , pt2 )
// Dereferencing the
// pointer to pointer
fmt . Println ( "Value at the address of pt2 is or *pt2 = " , * pt2 )
// double pointer will give the value of variable V
fmt . Println ( "*(Value at the address of pt2 is) or **pt2 = " , * * pt2 )
}
// The Value of Variable V is = 100
// Address of variable V is = 0x414020
// The Value of pt1 is = 0x414020
// Address of pt1 is = 0x40c128
// The value of pt2 is = 0x40c128
// Value at the address of pt2 is or *pt2 = 0x414020
// *(Value at the address of pt2 is) or **pt2 = 100ไปยังมีคอลเลกชันขยะ
ในการจัดสรรหน่วยความจำ Go มี 2 ดั้งเดิม new & make
ใหม่ จัดสรร; เริ่ม ต้น
ตัวสร้างและตัวอักษรส่วนประกอบ
// A lot of boiler plate
func NewFile ( fd int , name string ) * File {
if fd < 0 {
return nil
}
f := new ( File )
f . fd = fd
f . name = name
f . dirinfo = nil
f . nepipe = 0
return f
}
// Using a composite literal
func NewFile ( fd int , name string ) * File {
if fd < 0 {
return nil
}
f := File { fd , name , nil . 0 }
return & f // Return the address of a local variable. The storage associated with the variable survives after the function returns.
// return &File{fd, name, nil, 0}
// return &File{fd: fd, name: name}
} เป็นกรณีที่ จำกัด หากตัวอักษรคอมโพสิตไม่มีฟิลด์เลยมันจะสร้างค่าศูนย์สำหรับประเภท นิพจน์ new(File) & &File{} เทียบเท่า
ตัวอักษรคอมโพสิตสามารถสร้างขึ้นได้สำหรับอาร์เรย์ชิ้นและแผนที่โดยมีฉลากภาคสนามเป็นดัชนีหรือปุ่มแผนที่ตามความเหมาะสม
ar := [ ... ] string { Enone : "no error" , Einval : "invalid argument" }
sl := [] string { Enone : "no error" , Einval : "invalid argument" }
ma := map [ int ] string { Enone : "no error" , Einval : "invalid argument" } /* defining_own_type.go */
package main
import "fmt"
type NameAge struct {
name string // both non exported fiedls
age int
}
func main () {
a := new ( NameAge )
a . name = "Kien"
a . age = 25
fmt . Printf ( "%v n " , a ) // &{Kien, 25}
} struct {
x , y int
A * [] int
F func ()
}วิธีการ:
func doSomething1 ( n1 * NameAge , n2 int ) { /* */ }
// method call
var n * NameAge
n . doSomething1 ( 2 ) func ( n1 * NameAge ) doSomething2 ( n2 int ) { /* */ }หมายเหตุ : หาก X เป็นชุดวิธีการที่อยู่ & & X มี m, xm () เป็นชวเลขสำหรับ (& x) .m ()
// A mutex is a data type with two methods, Lock & Unlock
type Mutex struct { /* Mutex fields */ }
func ( m * Mutex ) Lock () { /* Lock impl */ }
func ( m * Mutext ) Unlock { /* Unlock impl */ }
// NewMutex is equal to Mutex, but it does not have any of the methods of Mutex.
type NewMutex Mutex
// PrintableMutex hash inherited the method set from Mutex, contains the methods
// Lock & Unlock bound to its anonymous field Mutex
type PrintableMutex struct { Mutex } FROM b []byte i []int r []rune s string f float32 i int
TO
[]byte . []byte(s)
[]int . []int(s)
[]rune []rune(s)
string string(b) string(i) string(r) .
float32 . float32(i)
int int(f) .
string เป็นชิ้นของไบต์หรือรูน mystring := "hello this is string"
byteslice := [] byte ( mystring )
runeslice := [] rune ( string ) b := [] byte { 'h' , 'e' , 'l' , 'l' , 'o' } // Composite literal
s := string ( b )
i := [] rune ( 26 , 9 , 1994 )
r := string ( i )สำหรับค่าตัวเลข:
uint8(int)int(float32) สิ่งนี้จะทิ้งส่วนเศษส่วนจากค่าจุดลอยตัวfloat32(int)ประเภทและการแปลงที่ผู้ใช้กำหนด
type foo struct { int } // Anonymous struct field
type bar foo // bar is an alias for foo
var b bar = bar { 1 } // Declare `b` to be a `bar`
var f foo = b // Assign `b` to `f` --> Cannot use b (type bar) as type foo in assignment
var f foo = foo ( b ) // OK! /* a struct type S with 1 field, 2 methods */
type S struct { i int }
func ( p * S ) Get () int { return p . i }
func ( p * S ) Put ( v int ) { p . i = v }
/* an interface type */
type I interface {
Get () int
Put () int
}
/* S is a valid implementation for interface I */ func f ( p I ) {
fmt . Println ( p . Get ())
p . Put ( 1 )
}
var s S
/* Because S implements I, we can call the
function f passing in a pointer to a value
of type S */
/* The reason we need to take the address of s,
rather than a value of type S, is because
we defined the methods on s to operae on pointers */
f ( & s )ความจริงที่ว่าคุณไม่จำเป็นต้องประกาศว่าประเภทใช้อินเทอร์เฟซหรือไม่หมายถึงการใช้รูปแบบของการพิมพ์เป็ด นี่ไม่ใช่การพิมพ์เป็ดบริสุทธิ์เพราะเมื่อเป็นไปได้ผู้ร้องเรียน GO จะตรวจสอบอย่างคงที่ว่าประเภทนั้นใช้ inerface หรือไม่ อย่างไรก็ตาม GO นั้นมีแง่มุมที่มีพลวัตอย่างหมดจดซึ่งคุณสามารถแปลงจากอินเทอร์เฟซหนึ่งไปยังอีกอินเทอร์เฟซ ในกรณีทั่วไปการแปลงนั้นจะถูกตรวจสอบในเวลาทำงาน หากการแปลงไม่ถูกต้อง - หากประเภทของค่าที่เก็บไว้ในค่าอินเตอร์เฟสที่มีอยู่จะไม่เป็นไปตามอินเตอร์เฟสที่กำลังแปลง - โปรแกรมจะล้มเหลวด้วยข้อผิดพลาดเวลารัน
package main
import "fmt"
type Duck interface {
Quack ()
}
type Donald struct {
}
func ( d Donald ) Quack () {
fmt . Println ( "quack quack!" )
}
type Daisy struct {
}
func ( d Daisy ) Quack () {
fmt . Println ( "-quack -quack" )
}
func sayQuack ( duck Duck ) {
duck . Quack ()
}
type Dog struct {
}
func ( d Dog ) Bark () {
fmt . Println ( "go go" )
}
func main () {
donald := Donald {}
sayQuack ( donald ) // quack
daisy := Daisy {}
sayQuack ( daisy ) // --quack
dog := Dog ()
sayQuack ( dog ) // compile error - cannot use dog (type Dog) as type Duck
} อินเทอร์เฟซของ Go ช่วยให้คุณใช้ duck typing เหมือนที่คุณทำในภาษาไดนามิกล้วนๆเช่น Python แต่ยังคงมีคอมไพเลอร์จับข้อผิดพลาดที่เห็นได้ชัดเช่นผ่าน int ที่วัตถุที่มีวิธี Read หรือเช่นเรียกวิธี Read ด้วยจำนวนอาร์กิวเมนต์ที่ไม่ถูกต้อง
type R struct { i int }
func ( p * R ) Get () int { return p . i }
func ( p * R ) Put ( v int ) { p . i = v }
func f ( p I ) {
switch t := p .( type ) {
case * S :
case * R :
default :
}
} func g ( something interface {}) int {
return something .( I ). Get ()
}.(I) เป็นประเภทการยืนยันที่แปลง something เป็นอินเทอร์เฟซของประเภท I หากเรามีประเภทเราสามารถเรียกใช้ฟังก์ชัน Get() s = new ( S )
fmt . Println ( g ( s ))วิธีการเป็นฟังก์ชันที่มีตัวรับสัญญาณ
คุณสามารถกำหนดวิธีการใด ๆ ในทุกประเภท (ยกเว้นในประเภทที่ไม่ใช่ท้องถิ่นซึ่งรวมถึงประเภทในตัว: ประเภท int ไม่สามารถมีวิธีการ)
วิธีการเกี่ยวกับประเภทอินเตอร์เฟส
โดยการประชุมอินเทอร์เฟซหนึ่งวิธีมีการตั้งชื่อโดยชื่อวิธีบวกคำต่อท้าย -er: Reader, Writer, Formatter, ...
ตัวชี้ตัวชี้และตัวชี้แบบตัวชี้
func ( s * MyStruct ) pointerMethod () {} // method on pointer
func ( s MyStruct ) valueMethod () {} // method on value package main
import "fmt"
type Mutatable struct {
a int
b int
}
func ( m Mutatable ) StayTheSame () {
m . a = 5
m . b = 7
}
func ( m * Mutatable ) Mutate () {
m . a = 5
m . b = 7
}
func main () {
m := & Mutatable { 0 , 0 }
fmt . Println ( m )
m . StayTheSame ()
fmt . Println ( m )
m . Mutate ()
fmt . Println ( m )
}struct ขนาดใหญ่เช่นมันจะถูกกว่ามากในการใช้ตัวรับสัญญาณตัวชี้struct ขนาดเล็กเครื่องรับค่ามีราคาถูกมากดังนั้นเว้นแต่ความหมายของวิธีการต้องใช้ตัวชี้ตัวรับค่ามีประสิทธิภาพและชัดเจน package main
import "fmt"
func do ( i interface {}) {
switch v := i .( type ) {
case int :
fmt . Printf ( "Twice %v is %v n " , v , v * 2 )
case string :
fmt . Printf ( "%q is %v bytes long n " , v , len ( v ))
default :
fmt . Printf ( "I don't know about type %T! n " , v )
}
}
func main () {
do ( 21 )
do ( "hello" )
do ( true )
}
// Twice 21 is 42
// "hello" is 5 bytes long
// I don't know about type bool! ready ( "Tea" , 2 ) // Normal function call
go ready ( "Tea" , 2 ) // .. Bum! Here is goroutine
/* X ready example */
package main
import (
"fmt"
"time"
)
func ready ( w string , sec int ) {
time . Sleep ( time . Duration ( sec ) * time . Second )
fmt . Println ( w , "is ready!" )
}
func main () {
go ready ( "Tea" , 2 ) // Tea is ready - After 2 second (3)
go ready ( "Coffee" , 1 ) // Coffee is ready - After 1 second (2)
fmt . Println ( "I'm waiting" ) // Right away (1)
// If did not wait for the goroutines, the program would be terminated
// immediately & any running goroutines would die with it!
time . Sleep ( 5 * time . Second )
} /* Define a channel, we must also define the type of
the values we can send on the channel */
ci := make ( chan int )
cs := make ( chan string )
cf := make ( chan interface {})
ci <- 1 // Send the integer 1 to the channel ci
<- ci // Receive an integer from the channel ci
i := <- ci // Receive from the channel ci & store it in i package main
import (
"fmt"
"time"
)
var c chan int
func ready ( w string , sec int ) {
time . Sleep ( time . Duration ( sec ) * time . Second )
fmt . Println ( w , "is ready!" )
c <- 1
}
func main () {
c = make ( chan int )
go ready ( "Tea" , 2 )
go ready ( "Coffee" , 1 )
fmt . Println ( "I'm waiting" )
<- c // Wait until we receive a value from the channel
<- c
}ช่องทางบัฟเฟอร์:
ช่องทางบัฟเฟอร์มีความจุ
Buffered Channel ใช้เพื่อดำเนินการสื่อสารแบบอะซิงโครนัส
ช่องทางบัฟเฟอร์ไม่มีการรับประกันดังกล่าว
การรับจะบล็อกเฉพาะในกรณีที่ไม่มีค่าในช่องที่จะได้รับ
การส่งจะบล็อกเฉพาะในกรณีที่ไม่มีบัฟเฟอร์ที่จะวางค่าที่ถูกส่ง
ช่องทางที่ไม่บัฟเฟอร์:
ช่องทางที่ไม่ได้รับการบัฟเฟอร์ไม่มีความจุและดังนั้นจึงต้องมี goroutines ทั้งสองเพื่อพร้อมที่จะทำการแลกเปลี่ยนใด ๆ
ช่องทางที่ไม่ผ่านการบัฟเฟอร์ใช้เพื่อทำการสื่อสารแบบซิงโครนัสระหว่าง goroutines ช่องทางที่ไม่ได้รับการรับรองให้การรับประกันว่ามีการแลกเปลี่ยนระหว่าง 2 goroutines ดำเนินการทันทีที่ส่งและรับจะเกิดขึ้น
การซิงโครไนซ์เป็นพื้นฐานในการโต้ตอบระหว่างการส่งและรับในช่อง
unbuffered := make ( chan int ) // Unbuffered channel of integer type
buffered := make ( chan int , 10 ) // Buffered channel of integer typeselect L: for {
select {
case <- c :
i ++
if i > 1 {
break L
}
}
} package main
import "fmt"
func fibonacci ( c , quit chan int ) {
x , y := 0 , 1
for {
select {
case c <- x :
x , y = y , x + y
case <- quit :
fmt . Println ( "quit" )
return
}
}
}
func main () {
c := make ( chan int )
quit := make ( chan int )
go func () {
for i := 0 ; i < 10 ; i ++ {
fmt . Println ( <- c )
}
quit <- 0
}()
fibonacci ( c , quit )
}
// 2
// 3
// 5
// 8
// 13
// 21
// 34
// quit // Default selection
// The default case in a select is run if no other case is ready.
// Use a default case to try a send or receive without blocking:
// select {
// case i := <-c:
// // use i
// default:
// // receiving from c would block
// }
package main
import (
"fmt"
"time"
)
func main () {
tick := time . Tick ( 100 * time . Millisecond )
boom := time . After ( 500 * time . Millisecond )
for {
select {
case <- tick :
fmt . Println ( "tick." )
case <- boom :
fmt . Println ( "BOOM!" )
return
default :
fmt . Println ( " ." )
time . Sleep ( 50 * time . Millisecond )
}
}
}ในขณะที่ goroutines ของเราทำงานพร้อมกันพวกเขาไม่ได้ทำงานแบบขนาน! (อีกครั้งให้แน่ใจว่าคุณรู้ว่าการเกิดขึ้นพร้อมกันไม่ใช่ parralel!)
ด้วย runtime.GOMAXPROCS(n) หรือตั้งค่าตัวแปรสภาพแวดล้อม GOMAXPROCS คุณสามารถตั้งค่าจำนวน goroutines ที่สามารถทำงานแบบขนานได้
จากเวอร์ชัน 1.5 และสูงกว่า GOMAXPROCS จะเริ่มต้นถึงจำนวนแกน CPU
ch := make ( chan type , value )
// if value == 0 -> unbuffered
// if value > 0 -> buffer value elements x , ok = <- ch
/ * Where ok is set to True the channel is not closed & we 'v e read something
Otherwise ok is set to False . In that case the channel was closed & the value
received is a zero value of the channel 's type .io.Reader & io.Writerio.Reader เป็นอินเทอร์เฟซที่สำคัญในภาษา ฟังก์ชั่นจำนวนมาก (ถ้าไม่ใช่ทั้งหมด) ที่ต้องอ่านจากบางสิ่งบางอย่างใช้ io.Reader เป็นอินพุตio.Writer มีวิธี Writeio.Reader หรือ io.Writer สามารถใช้ไลบรารี GO มาตรฐานทั้งหมด ในประเภทนั้นได้os.Argsflag มีอินเทอร์เฟซที่ซับซ้อนมากขึ้นและยังให้วิธีการแยกวิเคราะห์ธงos/exec มีฟังก์ชั่นในการเรียกใช้คำสั่งภายนอกและเป็นวิธีการเปิดใช้งานคำสั่งจากภายในโปรแกรม GO import "os/exec"
cmd := exec . Command ( "/bin/ls" , "-l" )
// Just run without doing anything with the returned data
err := cmd . Run ()
// Capturing the standard output
buf , err := cmd . Output () // buf is byte slicenetDial เมื่อคุณ Dial เข้าสู่ระบบระยะไกลฟังก์ชั่นจะส่งคืนประเภทอินเตอร์เฟส Conn ซึ่งสามารถใช้ในการส่งและรับข้อมูล ฟังก์ Dial ได้เป็นนามธรรมที่เป็นนามธรรมของตระกูลและการขนส่งเครือข่าย conn , e := Dial ( "tcp" , "192.0.32.10:80" )
conn , e := Dial ( "udp" , "192.0.32.10:80" )
conn , e := Dial ( "tcp" , "[2620:0:2d0:200::10]:80" )GO 1.11 รวมถึงการสนับสนุนเบื้องต้นสำหรับโมดูลระบบการจัดการการพึ่งพาใหม่ของ GO ที่ทำให้ข้อมูลเวอร์ชันการพึ่งพาอย่างชัดเจนและง่ายต่อการจัดการ
go.mod ในไดเรกทอรีรากของทรี ซอร์สโค้ดโมดูลอาจอยู่นอก Gopath มีสี่คำสั่ง: module , require , replace , excluderequire require go.mod คำสั่ง GO ส่วน ใหญ่ เช่น 'Go Build' & ' go.mod Test' จะค้นหาโมดูลที่เหมาะสมโดยอัตโนมัติ ตัวอย่างเช่นหากการนำเข้าใหม่ของคุณสอดคล้องกับการพึ่งพา M ซึ่งมีรุ่นรีลีสที่ติดแท็กล่าสุดคือ v1.2.3 go.mod ของคุณจะจบลงด้วย require M v1.2.3 ซึ่งบ่งชี้ว่าโมดูล M เป็นการพึ่งพาเวอร์ชันที่อนุญาต> = v1.2.3 (และ <V2v1.2.3 )/vN at the end of the module paths used in go.mod files (eg, module github.com/my/mod/v2 , require github.com/my/mod/v2 v2.0.0 ) & in the package import path (eg, import "github.com/my/mod/v2/mypkg" ).go.mod , provides the directory is outside $GOPATH/src . (Inside $GOPATH/src , for compatibility, the go command still runs in the old GOPATH mode, even if a go.mod is found) # Create a directory outside of your GOPATH:
$ mkdir -p /tmp/scratchpad/hello
$ cd /tmp/scratchpad/hello
# Initialize a new module:
$ go mod init github.com/you/hello
go: creating new go.mod: module github.com/you/hello
# Write your code
$ cat << EOF > hello.go
package main
import (
"fmt"
"rsc.io/quote"
)
func main() {
fmt.Println(quote.Hello())
}
EOF
# Introduce `go mod tidy`
# Tidy makes sure go.mod matches the source code in the module.
# It adds any missing modules necessary to build the current module's
# packages and dependencies, and it removes unused modules that
# don't provide any relevant packages. It also adds any missing entries
# to go.sum and removes any unnecessary ones
$ go mod tidy t/s/hello ﳑ
go: finding module for package rsc.io/quote
go: downloading rsc.io/quote v1.5.2
go: found rsc.io/quote in rsc.io/quote v1.5.2
go: downloading rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
$ cat go.mod
module github.com/you/hello
require rsc.io/quote v1.5.2
# Add a new dependency often brings in other indirect dependencies too
# List the current module and all its dependencies
$ go list -m all
github.com/you/hello
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
# In addition to go.mod, there is a go.sum file containing the expected
# cryptographic hashes of the content of specific module versions
$ cat go.sum t/s/hello ﳑ
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
# Build & run
$ go build
$ ./hello
Hello, world. # From the output of go list -m all, we're using an untagged version of golang.org/x/text
# Let's upgrade to the latest tagged version
$ go get golang.org/x/text t/s/hello ﳑ
go: downloading golang.org/x/text v0.7.0
go: upgraded golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c = > v0.7.0
$ cat go.mod t/s/hello ﳑ
module github.com/you/hello
go 1.19
require rsc.io/quote v1.5.2
require (
golang.org/x/text v0.7.0 // indirect
rsc.io/sampler v1.3.0 // indirect
)
$ go list -m all t/s/hello ﳑ
github.com/you/hello
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f
golang.org/x/text v0.7.0
golang.org/x/tools v0.1.12
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0go mod tidy and Go does the rest.go tool provides go mod vendor command.go mod vendor command constructs a directory named vendor in the main module's root directory that contains copies of all packages needed to support builds and tests of packages in the main modules.go mod vendor also creates the file vendor/modules.txt that contains a list of vendored packages and the module versions they were copied from.vendor to your Version Control System, then copy this around. $ go mod vendor
# Main module's directory structure
$ tree -L 3
├── go.mod
├── go.sum
├── hello.go
└── vendor
├── golang.org
│ └── x
├── modules.txt
└── rsc.io
├── quote
└── samplergo tool defaults to downloading modules from the public Go module mirror: https://proxy.golang.org and also defaults to validating downloaded modules (regardless of source) against the public Go checksum database at https://sum.golang.org. export GOPROXY=https://goproxy.io,directgo command defaults to downloading modules from the public Go module mirror, therefore if you have private code, you most likely should configure the GOPRIVATE setting (such as go env -w GOPRIVATE=*.corp.com,github.com/secret/repo ), or the more fine-grained variants GONOPROXY or GONOSUMDB that support less frequent use cases. See the documentation for more details.go.work . The dependencies in this file can span multiple modules and anything declared in the go.work file will override dependencies in the module's go.mod .go.work file that specifies relative paths to the module directories of each the modules in the workspace. When no go.work file exists, the workspace consists of the single module containing the current directory.go.work files are defined in exactly the same way as for go.mod files. go 1.18
use . / my / first / thing
use . / my / second / thing
// or
// use (
// ./my/first/thing
// ./my/second/thing
// )
replace example . com / bad / thing v1 .4 .5 = > example . com / good / thing v1 .4 .5$ mkdir workspace
$ cd workspace
# Create hello module
$ mkdir hello
$ cd hello
$ go mod init eaxmple.com/hello
go: creating new go.mod: module example.com/hello
$ cat << EOF > hello.go
package main
import (
"fmt"
"golang.org/x/example/stringutil"
)
func main() {
fmt.Println(stringutil.Reverse("Hello"))
}
EOF
$ go mod tidy
go: finding module for package golang.org/x/example/stringutil
go: found golang.org/x/example/stringutil in golang.org/x/example v0.0.0-20220412213650-2e68773dfca0
$ go run example.com/hello
olleH
# Create the workspace
$ cd ../
$ go work init ./hello
$ tree
.
├── go.work
└── hello
├── go.mod
├── go.sum
└── hello.go
1 directory, 4 files
# Go command includes all the modules in the workspace as main modules. This allow us to refer to a package in the module
# even outside the module.
$ go run example.com/hello
olleH
# Download and modify the golang.org/x/example module
$ git clone https://go.googlesource.com/example
Cloning into ' example ' ...
remote: Total 165 (delta 27), reused 165 (delta 27)
Receiving objects: 100% (165/165), 434.18 KiB | 1022.00 KiB/s, done.
Resolving deltas: 100% (27/27), done.
# Add module to the workspace
$ go work use ./example
$ tree -L 1
.
├── example
├── go.work
└── hello
2 directories, 1 file
$ cat go.work
go 1.20
use (
./example
./hello
)
$ cd example/stringutil
# Create a new file
$ cat << EOF > toupper.go
package stringutil
import "unicode"
// ToUpper uppercases all the runes in its argument string.
func ToUpper(s string) string {
r := []rune(s)
for i := range r {
r[i] = unicode.ToUpper(r[i])
}
return string(r)
}
EOF
# Modify hello program
$ cd ../../hello
$ cat << EOF > hello.go
package main
import (
"fmt"
"golang.org/x/example/stringutil"
)
func main() {
fmt.Println(stringutil.ToUpper("Hello"))
}
EOF
$ cd ..
# Go command finds the example.com/hello module specified in the command line
# in the hello directory specified by the go.work file, and similiarly
# resolves the golang.org/x/example import using the go.work file.
$ go run example.com/hello
HELLOSource: https://go.dev/doc/modules/layout
Go projects can include packages, command-line programs or a combination of the two. This guide is organized by project type.
NOTE : throughout this document, file/package names are entirely arbitrary
project-root-directory/
go.mod
modname.go
modname_test.go
auth.go
auth_test.go
hash.go
hash_test.gomodname.go declares the package with: package modname
// ... package code here project-root-directory/
go.mod
auth.go
auth_test.go
client.go
main.gomain.go file contains func main , but this is just a convention. The “main” file can also be called modname.go (for an appropriate value of modname) or anything else. internal ; this prevents other modules from depending on packages we don't necessarily want to expose and support for external uses. Since other projects cannot import code from our internal directory, we're free to refactor its API and generally move things around without breaking external users. The project structure for a package is thus: project-root-directory/
internal/
auth/
auth.go
auth_test.go
hash/
hash.go
hash_test.go
go.mod
modname.go
modname_test.goproject-root-directory/
go.mod
modname.go
modname_test.go
auth/
auth.go
auth_test.go
token/
token.go
token_test.go
hash/
hash.go
internal/
trace/
trace.go module github . com / someuser / modname project-root-directory/
go.mod
internal/
... shared internal packages
prog1/
main.go
prog2/
main.gomain . A top-level internal directory can contain shared packages used by all commands in the repository.cmd directory; while this isn't strictly necessary in a repository that consists only of commands, it's very useful in a mixed repository that has both commands and importable packages, as we will discuss next. project-root-directory/
go.mod
modname.go
modname_test.go
auth/
auth.go
auth_test.go
internal/
... internal packages
cmd/
prog1/
main.go
prog2/
main.gointernal directory. Moreover, since the project is likely to have many other directories with non-Go files, it's a good idea to keep all Go commands together in a cmd directory: project-root-directory/
go.mod
internal/
auth/
...
metrics/
...
model/
...
cmd/
api-server/
main.go
metrics-analyzer/
main.go
...
... the project ' s other directories with non-Go codeGo models data input and output as a stream that flows from sources to targets. Data sources, such as files, network connections, or even some in-memory objects , can be modeled as streams of bytes from which data can be read or written to.
The most common usage of the fmt package is for writting to standard output and reading from standard input.
type metalloid struct {
name string
number int32
weight float64
}
func main () {
var metalloids = [] metalloid {
{ "Boron" , 5 , 10.81 },
...
{ "Polonium" , 84 , 209.0 },
}
file , _ := os . Create ( "./metalloids.txt" )
defer file . Close ()
for _ , m := range metalloids {
fmt . Fprintf (
file ,
"%-10s %-10d %-10.3f n " ,
m . name , m . number , m . weight ,
)
}
} The bufio package offers several functions to do buffered writing of IO streams using an `io.Writer interface.
In bytes package offers common primitives to achieve streaming IO on blocks of bytes stored in memory, represented by the bytes.Buffer byte. Since the bytes.Buffer type implements both io.Reader and io.Writer interfaces it is a great option to stream data into or out of memory using streaming IO primitives.
package main
import (
"encoding/json"
"fmt"
)
type Measurement struct {
Height int
Weight int
}
type Person struct {
Name string
Age int
Measurement Measurement // Nested object
}
func main () {
bob := & Person {
Name : "Bob" ,
Age : 20 ,
}
bobRaw , _ := json . Marshal ( bob )
fmt . Println ( string ( bobRaw ))
// Raw data without Measurement field
aliceRaw := [] byte ( `{"name": "Alice", "age": 23}` )
var alice Person
if err := json . Unmarshal ( aliceRaw , & alice ); err != nil {
panic ( err )
}
fmt . Printf ( "%+v n " , alice )
}
// {"Name":"Bob","Age":20,"Measurement":{"Height":190,"Weight":75}}
// {Name:Alice Age:23 Measurement:{Height:0 Weight:0}} package main
import (
"encoding/json"
"fmt"
)
type Measurement struct {
Height int `json:"height"`
Weight int `json:"weight"`
}
type Person struct {
Name string `json:"who"`
Age int `json:"how old"`
Measurement Measurement `json:"mm"`
}
func main () {
bob := & Person {
Name : "Bob" ,
Age : 20 ,
}
bobRaw , _ := json . Marshal ( bob )
fmt . Println ( string ( bobRaw ))
// Raw data without Measurement field
aliceRaw := [] byte ( `{"who": "Alice", "how old": 23, "mm": {"height": 150, "weight": 40}}` )
var alice Person
if err := json . Unmarshal ( aliceRaw , & alice ); err != nil {
panic ( err )
}
fmt . Printf ( "%+v" , alice )
}
// {"who":"Bob","how old":20,"mm":{"height":0,"weight":0}}
// {Name:Alice Age:23 Measurement:{Height:150 Weight:40}} package main
import (
"encoding/json"
"fmt"
)
func main () {
// Raw data without Measurement field
aliceRaw := [] byte ( `{"name": "Alice", "age": 23, "measurement": {"height": 150, "weight": 40}}` )
var alice map [ string ] interface {}
if err := json . Unmarshal ( aliceRaw , & alice ); err != nil {
panic ( err )
}
// the object stored in the "mesurement" key is also stored
// as a map[string]interface{} type, and its type is asserted
// the interface{} type
measurement := alice [ "measurement" ].( map [ string ] interface {})
fmt . Printf ( "%+v n " , alice )
fmt . Printf ( "%+v n " , measurement )
}
// map[age:23 measurement:map[height:150 weight:40] name:Alice]
// map[height:150 weight:40]omitempty property. package main
import (
"encoding/json"
"fmt"
)
type Measurement struct {
Height int `json:"height"`
Weight int `json:"weight"`
}
type Person struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
Measurement Measurement `json:"measurement"`
}
func main () {
bob := & Person {
Name : "Bob" ,
Measurement : Measurement {
Height : 190 ,
Weight : 75 ,
},
}
bobRaw , _ := json . Marshal ( bob )
fmt . Println ( string ( bobRaw ))
}
// Age field is ignored
// {"name":"Bob","measurement":{"height":190,"weight":75}}NOTE : There are a lot more helpful things in tips-notes. You may want to check it out.
Go Web Example
A basic HTTP server has a few key jobs to take care of:
package main
import (
"fmt"
"net/http"
)
func main () {
// Process dynamic request
http . HandleFunc ( "/" , func ( w http. ResponseWriter , r * http. Request ) {
fmt . Fprintf ( w , "Welcome to my website!" )
})
// Serving static assets
fs := http . FileServer ( http . Dir ( "static/" ))
http . Handle ( "/static/" , http . StripPrefix ( "/static/" , fs ))
// Accept connections
http . ListenAndServe ( ":80" , nil )
}A simple logging middleware.
// basic-middleware.go
package main
import (
"fmt"
"log"
"net/http"
)
func logging ( f http. HandlerFunc ) http. HandlerFunc {
return func ( w http. ResponseWriter , r * http. Request ) {
log . Println ( r . URL . Path )
f ( w , r )
}
}
func foo ( w http. ResponseWriter , r * http. Request ) {
fmt . Fprintln ( w , "foo" )
}
func bar ( w http. ResponseWriter , r * http. Request ) {
fmt . Fprintln ( w , "bar" )
}
func main () {
http . HandleFunc ( "/foo" , logging ( foo ))
http . HandleFunc ( "/bar" , logging ( bar ))
http . ListenAndServe ( ":8080" , nil )
} A middleware in itself simple takes a http.HandleFunc as one of its parameters, wraps it & returns a new http.HandlerFunc for the server to call.
Define a new type Middleware which makes it eventually easier to chain multiple middlewares together.
How a new middleware is created, boilerplate code:
func newMiddleware () Middleware {
// Create a new Middleware
middleware := func ( next http. HandlerFunc ) http. HandlerFunc {
// Define the http.HandlerFunc which is called by the server eventually
handler := func ( w http. ResponseWriter , r * http. Request ) {
// ... do middleware things
// Call the next middleware/handler in chain
next ( w , r )
}
// Return newly created handler
return handler
}
// Return newly created middleware
return middleware
} // advanced-middleware.go
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Middleware func (http. HandlerFunc ) http. HandlerFunc
// Logging logs all requests with its path & the time it took to process
func Logging () Middleware {
// Create a new Middleware
return func ( f http. HandlerFunc ) http. HandlerFunc {
// Define the http.HandlerFunc
return func ( w http. ResponseWriter , r * http. Request ) {
// Do middleware things
start := time . Now ()
defer func () { log . Println ( r . URL . Path , time . Since ( start )) }()
// Call the next middleware/handler in chain
f ( w , r )
}
}
}
// Method ensures that url can only be requested with a specific method, else returns a 400 Bad Request
func Method ( m string ) Middleware {
// Create a new Middleware
return func ( f http. HandlerFunc ) http. HandlerFunc {
// Define the http.HandlerFunc
return func ( w http. ResponseWriter , r * http. Request ) {
// Do middleware things
if r . Method != m {
http . Error ( w , http . StatusText ( http . StatusBadRequest ), http . StatusBadRequest )
return
}
// Call the next middleware/handler in chain
f ( w , r )
}
}
}
// Chain applies middlewares to a http.HandlerFunc
func Chain ( f http. HandlerFunc , middlewares ... Middleware ) http. HandlerFunc {
for _ , m := range middlewares {
f = m ( f )
}
return f
}
func Hello ( w http. ResponseWriter , r * http. Request ) {
fmt . Fprintln ( w , "hello world" )
}
func main () {
http . HandleFunc ( "/" , Chain ( Hello , Method ( "GET" ), Logging ()))
http . ListenAndServe ( ":8080" , nil )
}This section is mainly taken from: https://github.com/zalopay-oss/go-advanced/blob/master/ch3-rpc/ch3-01-rpc-go.md
// 13/rpc/rpcserver/main.go
package main
import (
"log"
"net"
"net/rpc"
)
type HelloService struct {}
// Only methods that satisfy these criteria will be made available for remote access; other methods will be ignored:
// - the method's type is exported.
// - the method is exported.
// - the method has two arguments, both exported (or builtin) types.
// - the method's second argument is a pointer.
// - the method has return type error.
// func (t *T) MethodName(argType T1, replyType *T2) error
func ( p * HelloService ) Hello ( request string , reply * string ) error {
* reply = "Hello " + request
return nil
}
func main () {
rpc . RegisterName ( "HelloService" , new ( HelloService ))
listener , err := net . Listen ( "tcp" , ":8081" )
if err != nil {
log . Fatal ( "Listen TCP error:" , err )
}
log . Println ( "Server is ready" )
for {
// accept connection
conn , err := listener . Accept ()
if err != nil {
log . Fatal ( "Accept error:" , err )
}
// serve client in another goroutine
go func () {
log . Println ( "Accept new client:" , conn . RemoteAddr ())
rpc . ServeConn ( conn )
}()
}
} // 13/rpc/rpcclient/main.go
package main
import (
"log"
"net/rpc"
)
func main () {
client , err := rpc . Dial ( "tcp" , "localhost:8081" )
if err != nil {
log . Fatal ( "Dialing error:" , err )
}
var reply string
if err = client . Call ( "HelloService.Hello" , "Kien" , & reply ); err != nil {
log . Fatal ( err )
}
log . Println ( reply )
} # Server
$ go run examples/13/rpc/rpcserver/main.go
2023/08/09 16:29:29 Server is ready
2023/08/09 16:29:30 Accept new client: 127.0.0.1:38728
2023/08/09 16:29:31 Accept new client: 127.0.0.1:38734
# Client
$ go run examples/13/rpc/rpcclient/main.go
2023/08/09 16:29:30 Hello Kien
$ go run examples/13/rpc/rpcclient/main.go
2023/08/09 16:29:31 Hello Kienprotoc : # Ubuntu
# https://grpc.io/docs/protoc-installation/#install-using-a-package-manager
$ sudo apt install -y protobuf-compiler
# install go plugin
$ go install github.com/golang/protobuf/protoc-gen-go@latesthello.proto : // version proto3
syntax = "proto3" ;
// generated package name
package main ;
message String {
string value = 1 ;
}Generate Golang source code:
gRPC is a high performance, open-source remote procedure call (RPC) framework that can run anywhere. It enables client and server applications to communicate transparently, and makes it easier to build connected systems.
The gRPC server implements the service interface and runs an RPC server to handle client calls to its service methods. On the client side, the client has a stub (referred to as just a client in some languages) that provides the same methods as the server.
This section is about the new packages be added.
unique packageSource: https://go.dev/blog/unique
var internPool map [ string ] string
// Intern returns a string that is equal to s but that may share storage with
// a string previously passed to Intern.
func Intern ( s string ) string {
pooled , ok := internPool [ s ]
if ! ok {
// Clone the string in case it's part of some much bigger string.
// This should be rare, if interning is being used well.
pooled = strings . Clone ( s )
internPool [ pooled ] = pooled
}
return pooled
}unique package introduces a function similar to Intern called Make. But it also differs from Intern in two important ways:Handle[T] has the property that two Handle[T] values are equal if and only if the values used to create them are equal. The comparison of two Handle[T] values is cheap: it comes down to a pointer comparison.net/netip package in the standard library, which interns values of type addrDetail , part of the netip.Addr structure.netip.Addr , while the fact that they're canonicalized mean netip.Addr values are more efficient to compare, since comparing zone names becaomes a simple pointer comparison. // Addr represents an IPv4 or IPv6 address (with or without a scoped
// addressing zone), similar to net.IP or net.IPAddr.
type Addr struct {
// Other irrelevant unexported fields...
// Details about the address, wrapped up together and canonicalized.
z unique. Handle [ addrDetail ]
}
// addrDetail indicates whether the address is IPv4 or IPv6, and if IPv6,
// specifies the zone name for the address.
type addrDetail struct {
isV6 bool // IPv4 is false, IPv6 is true.
zoneV6 string // May be != "" if IsV6 is true.
}
var z6noz = unique . Make ( addrDetail { isV6 : true })
// WithZone returns an IP that's the same as ip but with the provided
// zone. If zone is empty, the zone is removed. If ip is an IPv4
// address, WithZone is a no-op and returns ip unchanged.
func ( ip Addr ) WithZone ( zone string ) Addr {
if ! ip . Is6 () {
return ip
}
if zone == "" {
ip . z = z6noz
return ip
}
ip . z = unique . Make ( addrDetail { isV6 : true , zoneV6 : zone })
return ip
}There is the page lists a few resources for programmers interested in learning about the Golang.
Oops, actually you can refer to awesome-go for a complete list.