언어를 배울 수있는 Go 코드가 많지 않으며, 저만 실험 해본 것도 아닙니다. 따라서 언어에 대해 흥미로운 것을 발견했다면 여기에 예제를 게시하십시오.
나는 또한 찾고있다
- Go에서 일을하는 관용적 방법,
- Go로 "포팅 된"C / C ++ 스타일
- 구문에 대한 일반적인 함정,
- 정말 흥미로운 거죠.
언어를 배울 수있는 Go 코드가 많지 않으며, 저만 실험 해본 것도 아닙니다. 따라서 언어에 대해 흥미로운 것을 발견했다면 여기에 예제를 게시하십시오.
나는 또한 찾고있다
답변:
진술 연기
"defer"문은 주변 함수가 반환하는 순간까지 실행이 지연되는 함수를 호출합니다.
DeferStmt = "지연"표현식.
식은 함수 또는 메서드 호출이어야합니다. "defer"문이 실행될 때마다 함수 호출에 대한 매개 변수가 평가되고 새로 저장되지만 함수는 호출되지 않습니다. 지연된 함수 호출은 주변 함수가 반환되기 직전에 LIFO 순서로 실행되지만 반환 값 (있는 경우)이 평가 된 후에 실행됩니다.
lock(l);
defer unlock(l); // unlocking happens before surrounding function returns
// prints 3 2 1 0 before surrounding function returns
for i := 0; i <= 3; i++ {
defer fmt.Print(i);
}
최신 정보:
defer
처리 할 수있는 관용적 방법도 지금 panic
에 예외 같은 방식으로는 :
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)
}
Go 개체 파일에는 실제로 일반 텍스트 헤더가 포함되어 있습니다.
jurily@jurily ~/workspace/go/euler31 $ 6g euler31.go
jurily@jurily ~/workspace/go/euler31 $ cat euler31.6
amd64
exports automatically generated from
euler31.go in package "main"
import
$$ // exports
package main
var main.coin [9]int
func main.howmany (amount int, max int) (? int)
func main.main ()
var main.initdone· uint8
func main.init ()
$$ // local types
type main.dsigddd_1·1 struct { ? int }
$$
!
<binary segment>
나는 " i = 0; i < len; i++
이 시대에 왜 우리가 말해야 하는가?" 라는 문구와 함께 for-loop에 대해 불평하는 두 사람을 보았다 .
동의하지 않습니다. for 구문을 좋아합니다. 원하는 경우 긴 버전을 사용할 수 있지만 관용적 인 Go는
var a = []int{1, 2, 3}
for i, v := range a {
fmt.Println(i, v)
}
이 for .. range
구문은 모든 요소를 반복하며 인덱스 i
와 값이라는 두 가지 값을 제공 합니다 v
.
range
지도와 채널에서도 작동합니다.
당신이 싫어하는 경우 여전히 for
어떤 형태로, 당신은 정의 할 수 있습니다 each
, map
몇 줄에 등 :
type IntArr []int
// 'each' takes a function argument.
// The function must accept two ints, the index and value,
// and will be called on each element in turn.
func (a IntArr) each(fn func(index, value int)) {
for i, v := range a {
fn(i, v)
}
}
func main() {
var a = IntArr([]int{2, 0, 0, 9}) // create int slice and cast to IntArr
var fnPrint = func(i, v int) {
fmt.Println(i, ":", v)
} // create a function
a.each(fnPrint) // call on each element
}
인쇄물
0 : 2
1 : 0
2 : 0
3 : 9
나는 Go를 많이 좋아하기 시작했습니다. :)
range
그것이를위한 3 루프와 같은 코드로 컴파일 된 경우에만 좋다.
이것은 이 답변 의 번역입니다 .
package main
import (
"json"
"fmt"
"http"
"os"
"strings"
)
func die(message string) {
fmt.Printf("%s.\n", message);
os.Exit(1);
}
func main() {
kinopiko_flair := "https://stackoverflow.com/users/flair/181548.json"
response, _, err := http.Get(kinopiko_flair)
if err != nil {
die(fmt.Sprintf("Error getting %s", kinopiko_flair))
}
var nr int
const buf_size = 0x1000
buf := make([]byte, buf_size)
nr, err = response.Body.Read(buf)
if err != nil && error != os.EOF {
die(fmt.Sprintf("Error reading response: %s", err.String()))
}
if nr >= buf_size { die ("Buffer overrun") }
response.Body.Close()
json_text := strings.Split(string(buf), "\000", 2)
parsed, ok, errtok := json.StringToJson(json_text[0])
if ! ok {
die(fmt.Sprintf("Error parsing JSON %s at %s", json_text, errtok))
}
fmt.Printf("Your stackoverflow.com reputation is %s\n", parsed.Get ("reputation"))
}
.Read ()에 대한 도움을 주신 Scott Wales에게 감사드립니다 .
이것은 두 개의 문자열과 두 개의 버퍼로 여전히 상당히 투박해 보이므로 Go 전문가가 조언이 있으면 알려주십시오.
gofmt
귀하의 코드에 권장합니다 . :-)
다음은 Kinopiko의 게시물 에서 iota의 좋은 예입니다 .
type ByteSize float64
const (
_ = iota; // ignore first value by assigning to blank identifier
KB ByteSize = 1<<(10*iota)
MB
GB
TB
PB
YB
)
// This implicitly repeats to fill in all the values (!)
병렬 할당으로 변수를 바꿀 수 있습니다.
x, y = y, x
// or in an array
a[j], a[i] = a[i], a[j]
간단하지만 효과적인.
다음은 Effective Go 페이지 의 관용구입니다.
switch {
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
표현식이 제공되지 않으면 switch 문이 true로 전환됩니다. 그래서 이것은
if '0' <= c && c <= '9' {
return c - '0'
} else if 'a' <= c && c <= 'f' {
return c - 'a' + 10
} else if 'A' <= c && c <= 'F' {
return c - 'A' + 10
}
return 0
지금은 스위치 버전이 좀 더 깔끔해 보입니다.
Switch True
…)
유형 스위치 :
switch i := x.(type) {
case nil:
printString("x is nil");
case int:
printInt(i); // i is an int
case float:
printFloat(i); // i is a float
case func(int) float:
printFunction(i); // i is a function
case bool, string:
printString("type is bool or string"); // i is an interface{}
default:
printString("don't know the type");
}
패키지를 가져올 때 이름을 원하는대로 다시 정의 할 수 있습니다.
package main
import f "fmt"
func main() {
f.Printf("Hello World\n")
}
명명 된 결과 매개 변수
Go 함수의 반환 또는 결과 "매개 변수"에 이름을 지정하고 들어오는 매개 변수와 마찬가지로 일반 변수로 사용할 수 있습니다. 이름이 지정되면 함수가 시작될 때 해당 유형에 대해 0 값으로 초기화됩니다. 함수가 인수없이 return 문을 실행하면 결과 매개 변수의 현재 값이 반환 된 값으로 사용됩니다.
이름은 필수는 아니지만 코드를 더 짧고 명확하게 만들 수 있습니다. 문서입니다. nextInt의 결과 이름을 지정하면 반환 된 int가 어느 것인지 분명해집니다.
func nextInt(b []byte, pos int) (value, nextPos int) {
명명 된 결과는 초기화되고 장식되지 않은 반환에 연결되어 있기 때문에 명확하고 단순화 할 수 있습니다. 다음은이를 잘 사용하는 io.ReadFull의 버전입니다.
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
for len(buf) > 0 && err == nil {
var nr int;
nr, err = r.Read(buf);
n += nr;
buf = buf[nr:len(buf)];
}
return;
}
에서 제임스 Antill의 대답 :
foo := <-ch // This blocks.
foo, ok := <-ch // This returns immediately.
또한 잠재적 인 함정 : 수신 및 송신 연산자 의 미묘한 차이 :
a <- ch // sends ch to channel a
<-ch // reads from channel ch
/*
* How many different ways can £2 be made using any number of coins?
* Now with 100% less semicolons!
*/
package main
import "fmt"
/* This line took me over 10 minutes to figure out.
* "[...]" means "figure out the size yourself"
* If you only specify "[]", it will try to create a slice, which is a reference to an existing array.
* Also, ":=" doesn't work here.
*/
var coin = [...]int{0, 1, 2, 5, 10, 20, 50, 100, 200}
func howmany(amount int, max int) int {
if amount == 0 { return 1 }
if amount < 0 { return 0 }
if max <= 0 && amount >= 1 { return 0 }
// recursion works as expected
return howmany(amount, max-1) + howmany(amount-coin[max], max)
}
func main() {
fmt.Println(howmany(200, len(coin)-1))
}
int와 같은 프리미티브를 포함한 유형을 원하는만큼 재정의하고 다른 메소드를 연결할 수 있다는 점이 마음에 듭니다. RomanNumeral 유형을 정의하는 것과 같습니다.
package main
import (
"fmt"
"strings"
)
var numText = "zero one two three four five six seven eight nine ten"
var numRoman = "- I II III IV V VI VII IX X"
var aText = strings.Split(numText, " ")
var aRoman = strings.Split(numRoman, " ")
type TextNumber int
type RomanNumber int
func (n TextNumber) String() string {
return aText[n]
}
func (n RomanNumber) String() string {
return aRoman[n]
}
func main() {
var i = 5
fmt.Println("Number: ", i, TextNumber(i), RomanNumber(i))
}
인쇄되는
Number: 5 five V
RomanNumber()
호출은 INT의보다 구체적인 유형으로 int 형을 재정의, 본질적으로 캐스팅이다. 그리고 무대 뒤에서 Println()
전화 String()
합니다.
이것은 매우 중요한 진정한 관용구입니다. 데이터를 채널에 공급하고 나중에 닫는 방법입니다. 이것으로 간단한 반복자 (범위가 채널을 받아들이 기 때문에) 또는 필터를 만들 수 있습니다.
// return a channel that doubles the values in the input channel
func DoublingIterator(input chan int) chan int {
outch := make(chan int);
// start a goroutine to feed the channel (asynchronously)
go func() {
for x := range input {
outch <- 2*x;
}
// close the channel we created and control
close(outch);
}();
return outch;
}
채널 읽기 시간 초과 :
ticker := time.NewTicker(ns);
select {
case v := <- chan_target:
do_something_with_v;
case <- ticker.C:
handle_timeout;
}
Davies Liu 에게서 도난당했습니다 .
$ GOROOT / src에서 사용할 수있는 make 시스템 설정이 있습니다.
메이크 파일 설정
TARG=foobar # Name of package to compile
GOFILES=foo.go bar.go # Go sources
CGOFILES=bang.cgo # Sources to run cgo on
OFILES=a_c_file.$O # Sources compiled with $Oc
# $O is the arch number (6 for x86_64)
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
그런 다음 make test를 실행하여 자동화 된 테스트 도구를 사용하거나 make install을 사용하여 cgo의 패키지 및 공유 객체를 $ GOROOT에 추가 할 수 있습니다.
Go의 또 다른 흥미로운 점은 godoc
. 다음을 사용하여 컴퓨터에서 웹 서버로 실행할 수 있습니다.
godoc -http=:8080
여기서 8080은 포트 번호이고 golang.org의 전체 웹 사이트는에서 사용할 수 있습니다 localhost:8080
.
이것은 스택의 구현입니다. 유형에 메소드를 추가하는 방법을 보여줍니다.
나는 조각으로의 스택 부분을 확인하고 조각의 속성을 사용하고 싶어하지만 난없이 작업에 그것을 가지고 있지만 type
, 나는 함께 조각을 정의하는 구문을 볼 수 없었다 type
.
package main
import "fmt"
import "os"
const stack_max = 100
type Stack2 struct {
stack [stack_max]string
size int
}
func (s *Stack2) push(pushed_string string) {
n := s.size
if n >= stack_max-1 {
fmt.Print("Oh noes\n")
os.Exit(1)
}
s.size++
s.stack[n] = pushed_string
}
func (s *Stack2) pop() string {
n := s.size
if n == 0 {
fmt.Print("Underflow\n")
os.Exit(1)
}
top := s.stack[n-1]
s.size--
return top
}
func (s *Stack2) print_all() {
n := s.size
fmt.Printf("Stack size is %d\n", n)
for i := 0; i < n; i++ {
fmt.Printf("%d:\t%s\n", i, s.stack[i])
}
}
func main() {
stack := new(Stack2)
stack.print_all()
stack.push("boo")
stack.print_all()
popped := stack.pop()
fmt.Printf("Stack top is %s\n", popped)
stack.print_all()
stack.push("moo")
stack.push("zoo")
stack.print_all()
popped2 := stack.pop()
fmt.Printf("Stack top is %s\n", popped2)
stack.print_all()
}
fmt.Printf(...); os.Exit();
, 당신은 사용할 수 있습니다 panic(...)
.
이동에서 C 코드 호출
c 런타임을 사용하여 더 낮은 수준의 go에 액세스 할 수 있습니다.
C 함수는 다음과 같은 형식입니다.
void package·function(...)
(점 구분자는 유니 코드 문자입니다.) 여기서 인수는 기본 go 유형, 슬라이스, 문자열 등일 수 있습니다. 값 호출을 반환하려면
FLUSH(&ret)
(두 개 이상의 값을 반환 할 수 있음)
예를 들어 함수를 만들려면
package foo
bar( a int32, b string )(c float32 ){
c = 1.3 + float32(a - int32(len(b))
}
C에서 사용
#include "runtime.h"
void foo·bar(int32 a, String b, float32 c){
c = 1.3 + a - b.len;
FLUSH(&c);
}
여전히 go 파일에서 함수를 선언해야하며 메모리를 직접 관리해야합니다. 이것을 사용하여 외부 라이브러리를 호출 할 수 있는지 잘 모르겠습니다. cgo를 사용하는 것이 더 나을 수 있습니다.
런타임에 사용 된 예제는 $ GOROOT / src / pkg / runtime을 참조하십시오.
go와 C ++ 코드를 연결하려면 this answer 을 참조하십시오 .
다음은 sqlite3 패키지를 사용하는 이동 예제입니다.
당신이 봤어 이 이야기를 ? 당신이 할 수있는 멋진 것들을 많이 보여줍니다.
다른 답변을 기반으로하지만 크기 제한이없는 슬라이스 추가를 사용하는 스택입니다.
package main
import "fmt"
import "os"
type Stack2 struct {
// initial storage space for the stack
stack [10]string
cur []string
}
func (s *Stack2) push(pushed_string string) {
s.cur = append(s.cur, pushed_string)
}
func (s *Stack2) pop() (popped string) {
if len(s.cur) == 0 {
fmt.Print("Underflow\n")
os.Exit(1)
}
popped = s.cur[len(s.cur)-1]
s.cur = s.cur[0 : len(s.cur)-1]
return
}
func (s *Stack2) print_all() {
fmt.Printf("Stack size is %d\n", len(s.cur))
for i, s := range s.cur {
fmt.Printf("%d:\t%s\n", i, s)
}
}
func NewStack() (stack *Stack2) {
stack = new(Stack2)
// init the slice to an empty slice of the underlying storage
stack.cur = stack.stack[0:0]
return
}
func main() {
stack := NewStack()
stack.print_all()
stack.push("boo")
stack.print_all()
popped := stack.pop()
fmt.Printf("Stack top is %s\n", popped)
stack.print_all()
stack.push("moo")
stack.push("zoo")
stack.print_all()
popped2 := stack.pop()
fmt.Printf("Stack top is %s\n", popped2)
stack.print_all()
}
const ever = true
for ever {
// infinite loop
}
for { /* infinite loop */ }
충분합니다.
forever
키워드가 마음에 들어요 . Qt조차도 그것에 대한 매크로를 가지고 있습니다.
for ever
(변수를 선언 한 후) 원하는 경우 Go에서 할 수있는 귀여운 것입니다. 영어처럼 보입니다 (공백 모듈로).
#define ever (;;)
test
메인 디렉토리 에는 작은 프로그램이 많이 있습니다 . 예 :
peano.go
계승을 인쇄합니다.hilbert.go
행렬 곱셈이 있습니다.iota.go
이상한 iota의 예가 있습니다.