
목차
unique 패키지Golang 문서를 찾는 것은 큰 문제가 아닙니다. 좋은 리소스가 많이 있으며, 하나를 선택하고 학습 여정을 시작하십시오. 나는 주로 학습 Go -Miek Gieben을 따릅니다.
참고 :이 문서의 모든 예제는 섹션별로 지명 된 디렉토리에 저장됩니다. 섹션 X의 모든 명령이 example/x 디렉토리에서 실행될 것이라고 가정하므로 GO 스크립트 파일을위한 전체 경로를 작성하지 않습니다.
/* 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 -int- 기계에 적합한 길이를 가지고 있습니다 (32 비트 기계 - 32 비트, 64 비트 기계 -64 비트)에 적합합니다.int8 , int16 , int32 , int64 & byte ( uint8 의 별칭), uint8 , uint16 , uint32 , uint64 입니다.float32 , 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 문자 (UTF -8으로 인코딩 됨 )를 의미합니다. 주목하십시오! 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 int32 의 별칭입니다 (문자열의 문자를 반복 할 때 사용).
복소수 : complex128 (64 비트 real & Imaginary Parts) 또는 complex32 .
오류 : GO는 error.var e 라는 오류를 위해 특별히 내장형 유형을 가지고 있습니다.
GO 1.18은 일반 유형을 지원합니다. Go 1.18이 제공하는 제네릭 구현은 유형 매개 변수 제안을 따르고 개발자는 유형 및 함수 선언에 선택적 유형 매개 변수를 추가 할 수 있습니다. 체크 아웃 Golang의 제네릭 튜토리얼.
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 XOR, &^ 비트 명확성. 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 다양한 유형의 커뮤니케이션 중에서 선택하는 데 사용됩니다.interface .struct 추상 데이터 유형에 사용됩니다.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 에 표현이 없으면 true 전환이 켜집니다.if-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 스트링, 맵, 슬라이스 및 어레이의 길이를 반환하는 데 사용됩니다.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 ]슬라이스는 슬라이스의 데이터를 복사하지 않습니다. 원래 배열을 가리키는 새 조각을 만듭니다. 이로 인해 슬라이스 작동은 어울리는 배열 표시만큼 효율적으로 만듭니다. 따라서 리 슬라이스의 요소 (슬라이스 자체가 아님)를 수정하면 원래 슬라이스의 요소가 수정됩니다.
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 에 대한 포인터입니다. 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
}def func(x int) {/*....*/}(5) )를 사용하는 경우 defer 값을 변경할 수도 있습니다. 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는 공황에 대한 부름처럼 행동합니다. 현재 고루 틴의 모든 기능이 반환 될 때까지 프로세스가 스택을 계속합니다.이 시점에서 프로그램이 충돌합니다. 공황을 직접 호출하여 공황을 시작할 수 있습니다. 또한 바운드 외 배열 액세스와 같은 런타임 오류로 인해 발생할 수 있습니다. /* 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 로 가져 오지만 compress/gzip 이 아닌 gzip 이름이 있습니다.ring.Ring 패키지 (패키지 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 함수와 마찬가지로 패키지가 초기화되면 GO에서 init 함수를 호출합니다. 인수는 없으며 가치를 반환하지 않습니다. init 기능은 GO에 의해 암시 적으로 선언됩니다. 파일이나 패키지에 여러 개의 init 기능을 가질 수 있습니다. 파일에서 init 함수 실행 순서는 외관 순서에 따라됩니다.null 컨테이너 역할을하는 GO의 특수 문자입니다.go 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/packageHTTP 테스트 :
net/http/httptest 하위 패키지는 HTTP 서버 및 클라이언트 코드의 테스트 자동화를 용이하게합니다.httptest.ResponseRecorder 테스트 된 기능에서 http.responsewriter에 대한 상태 변경을 검사하여 HTTP 핸들러 방법을 행사하기위한 단위 테스트 기능을 제공하도록 특별히 설계되었습니다.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 C의 printf & scanf 와 유사한 함수와 함께 형식화 된 I/O를 구현합니다. 형식 동사는 C에서 파생되지만 더 간단합니다. 사용할 수있는 일부 동사 (%-시합) :
IO : 패키지는 I/O 프리미티브에 대한 기본 인터페이스를 제공합니다. 주요 작업은 패키지 os 의 기존 구현을 패키지 OS의 기존 구현을 기능을 추상화하는 공유 공개 인터페이스와 다른 관련 프리미티브를 공유하는 공유 인터페이스로 래핑하는 것입니다.
Bufio :이 패키지는 버퍼링 된 I/O를 구현합니다. io.reader 또는 io.writer 객체를 랩핑하여 인터페이스를 구현하지만 텍스트 I/O에 대한 버퍼링 및 일부 도움말을 제공하는 다른 객체 (Reader 또는 Writer)를 만듭니다.
정렬 : 정렬 패키지는 배열 정렬 및 사용자 정의 컬렉션을 정렬하기위한 프리미티브를 제공합니다.
STRCONV : STRCONV 패키지는 기본 데이터 유형의 문자열 표현으로의 전환을 구현합니다.
OS : OS 패키지는 운영 체제 기능에 대한 플랫폼 독립 인터페이스를 제공합니다. 디자인은 유닉스와 비슷합니다.
동기화 : 패키지 동기화는 상호 제외 잠금과 같은 기본 동기화 프리미티브를 제공합니다.
플래그 : 플래그 패키지는 명령 줄 플래그 구문 분석을 구현합니다.
인코딩/JSON : 인코딩/JSON 패키지는 RFC 4627에 정의 된대로 JSON 객체의 인코딩 및 디코딩을 구현합니다.
HTML/템플릿 : HTML과 같은 텍스트 출력을 생성하기위한 데이터 중심 템플릿.
NET/HTTP : NET/HTTP 패키지는 HTTP 요청, 답장 및 URL 및 확장 가능한 HTTP 서버 및 기본 HTTP 클라이언트를 제공합니다.
안전하지 않은 : 안전하지 않은 패키지에는 GO 프로그램의 안전성을 중심으로하는 작업이 포함되어 있습니다. 일반적 으로이 패키지가 필요하지 않지만 안전하지 않은 GO 프로그램이 가능하다는 것을 언급 할 가치가 있습니다.
반사 : 반사 패키지는 런타임 반사를 구현하여 프로그램이 임의의 유형으로 객체를 조작 할 수 있도록합니다. 일반적인 사용은 정적 유형 인터페이스 {}로 값을 취하고 유형을 호출하여 동적 유형 정보를 추출하는 것입니다.
OS/EXEC : OS/EXEC 패키지는 외부 명령을 실행합니다.
Go는 포인터가 있지만 포인터 아르트 미티는 없으므로 C에서 알 수있는 포인터보다 참조처럼 작용합니다.
var p * int
p ++this 를 확인하십시오.포인터는 유용합니다. GO에서 함수를 호출 할 때 변수는 통과 별 입니다. 따라서 효율성과 기능에서 전달 된 값을 수정할 수있는 가능성을 위해 포인터가 있습니다.
포인터 유형 ( * type) 및 주소 (&) 연산자 * : 변수가 var x int 로 선언되면 &x ( "x")는 정수 변수 (유형 * int 값)에 대한 포인터를 산출합니다. 이 값이 p 라고하는 경우, " p x 로 가리킨다"라고 말하거나 동등하게 " p x 의 주소가 포함됩니다"라고합니다. p 점이 작성되는 변수 *p . 표현 *p 해당 변수의 값, int, 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"새로 선언 된 모든 변수는 제로 값으로 할당되며 포인터는 다르지 않습니다. 새로 선언 된 포인터, 또는 아무것도 가리키는 포인터에는 nil 값이 있습니다.
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 = 100Go에는 쓰레기 수거도 있습니다.
메모리를 할당하려면 2 개의 프리미티브, new & make 있습니다.
새로운 할당; 초기화 하십시오 .
생성자 및 Compiste Literals
// 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}
} 제한적인 경우, 복합 문자에 필드가 전혀 포함되어 있지 않으면 유형에 대한 값이 0이됩니다. 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 Complier는 유형이 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의 인터페이스를 사용하면 Python과 같은 순수한 역동적 인 언어로처럼 duck typing 사용할 수 있지만 여전히 Read 메소드가있는 객체가 예상되는 int 전달하거나 잘못된 수의 인수가있는 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) 유형 I의 인터페이스로 something 변환하는 유형 어설 션입니다. 유형이 있으면 Get() 함수를 호출 할 수 있습니다. s = new ( S )
fmt . Println ( g ( s ))메소드는 수신기가있는 함수입니다.
모든 유형에서 메소드를 정의 할 수 있습니다 (로컬이 아닌 유형 제외에는 내장 유형이 포함됩니다. 유형 int 메소드가 없습니다).
인터페이스 유형의 메소드
컨벤션별로, 1- 메드 인터페이스는 메소드 이름과 -er 접미사 : 독자, 작가, 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
}버퍼링 된 채널 :
버퍼링 된 채널에는 용량이 있습니다.
버퍼링 된 채널은 비동기 통신을 수행하는 데 사용됩니다.
버퍼링 된 채널에는 그러한 보장이 없습니다.
수신은 채널에 수신 할 가치가없는 경우에만 차단됩니다.
전송은 전송되는 값을 배치 할 수있는 버퍼가없는 경우에만 차단됩니다.
부패하지 않은 채널 :
부패하지 않은 채널에는 용량이 없으므로 두 고어 라인이 모두 교환 할 준비가되어 있어야합니다.
부패하지 않은 채널은 고어 라틴 간의 동기 통신을 수행하는 데 사용됩니다. 부패하지 않은 채널은 2 개의 고 루틴 사이의 교환이 송신 및 수신이 발생하는 순간에 수행되도록 보장합니다.
동기화는 채널에서 보내기와 수신 사이의 상호 작용에서 기본입니다.
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 설정하면 병렬로 실행할 수있는 Goroutine 수를 설정할 수 있습니다.
버전 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.Writer 입니다.io.Reader 는 언어로 중요한 인터페이스입니다. 무언가에서 읽어야하는 많은 (전부는 아니지만) 기능을 io.Reader 입력으로 가져갑니다.io.Writer 에는 Write 방법이 있습니다.io.Reader 또는 io.Writer 인터페이스를 충족 시키면 전체 표준 GO 라이브러리를 해당 유형에서 사용할 수 있습니다 .os.Args 를 통해 프로그램 내에서 사용할 수 있습니다.flag 패키지에는보다 정교한 인터페이스가 있으며 플래그를 구문 분석하는 방법도 제공했습니다.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 slicenet 에서 찾을 수 있습니다.Dial 입니다. 원격 시스템으로 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 파일이있는 Go 소스 파일의 트리에 의해 정의됩니다. 모듈 소스 코드는 Gopath 외부에있을 수 있습니다. 4 가지 지침이 있습니다 : module , require , replace , exclude .go.mod 에서 아직 require 포함되지 않은 소스 코드에 새 가져 오기를 추가하면 대부분의 GO 명령 'GO Build'& 'GO Test'와 같은 대부분의 GO 명령은 적절한 모듈을 자동으로 조회하고 새로운 직접 종속성의 require 높은 버전을 모듈의 go.mod 에 추가합니다. 예를 들어, 새 가져 오기가 최신 태그 릴리스 버전 인 v1.2.3 인 종속성 M에 해당하는 경우 모듈의 go.mod require M v1.2.3 . 이는 Module M이 허용 버전> = v1.2.3의 종속성임을 나타냅니다 (v2, v2, v2는 v1과 적합하지 않은 것으로 간주됨).v1.2.3 과 같은 태그 포함)를 따르십시오.go.mod 파일에 사용되는 모듈 경로의 끝에 A /vN 으로 포함되어야 합니다 (예 : module github.com/my/mod/v2 require github.com/my/mod/v2 v2.0.0 ) 및 패키지 가져 오기 경로 (eg, import, import, 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.