Go 예제 및 관용구 [닫기]


91

언어를 배울 수있는 Go 코드가 많지 않으며, 저만 실험 해본 것도 아닙니다. 따라서 언어에 대해 흥미로운 것을 발견했다면 여기에 예제를 게시하십시오.

나는 또한 찾고있다

  • Go에서 일을하는 관용적 방법,
  • Go로 "포팅 된"C / C ++ 스타일
  • 구문에 대한 일반적인 함정,
  • 정말 흥미로운 거죠.

8 비트 또는 16 비트와 같은 ARM 지원. D 언어는 여전히 그렇지 않습니다.

1
라이브러리 ( golang.org/pkg )는 go 사용 방법을 배울 수있는 훌륭한 소스입니다. 개인적으로 데이터 구조가 어떻게 구현되는지 배우는 것이 언어를 배우는 데 도움이된다는 것을 알게되었습니다.
tkokasih

답변:


35

진술 연기

"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)
}

17
좋은 오래된 RAII (명시 적)처럼 보입니다.
Konrad Rudolph

4
Go에 대해 많이 읽었 기 때문에 +1했지만 (당신이 보여줄 때까지) 여전히 이것을 보지 못했습니다!
u0b34a0f6ae

영리하지만, FIFO 순서 (위에서 아래로)로 실행되는 명령문을 연기하는 것이 더 이해가되지만 아마도 그것은
나일


4
@Mike : "try : .. finally :"블록과 비교하면 LIFO는 같은 방식으로 중첩됩니다. 리소스 열기 / 닫기 쌍 등의 경우 이와 같은 중첩이 유일하게 의미가 있습니다 (첫 번째 열기가 마지막에 닫힘).
u0b34a0f6ae

25

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>

6
그것은 관용적 예보다 숨겨진 기능에 더
가깝습니다

22

나는 " 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 루프와 같은 코드로 컴파일 된 경우에만 좋다.
Thomas Ahle 2014-06-30

19

가서 당신의 stackoverflow 평판을 얻으십시오

이것은 이 답변 의 번역입니다 .

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 전문가가 조언이 있으면 알려주십시오.


서식에 어떤 문제가 있었는지 잘 모르겠습니다. 복원했습니다.

5
Go 작성자가 gofmt귀하의 코드에 권장합니다 . :-)
ℝaphink 2009

컴파일 할 수 없습니다 : $ ../go/src/cmd/6g/6g SO.go SO.go : 34 : undefined : json.StringToJson
ℝaphink

@Raphink : 내가 만든 이후로 언어가 변경되었습니다.

예, StringToJson과 가장 가까운 것이 무엇인지 알고 있습니까? 이전에는 빌더를 내부적으로 설정했지만 이제는 미리 정의 된 기본 구조를 자체적으로 제공해야합니까?
macbirdie 2010 년

19

다음은 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 (!)

5
세미콜론은 필요하지 않습니다.
mk12 2013

18

병렬 할당으로 변수를 바꿀 수 있습니다.

x, y = y, x

// or in an array
a[j], a[i] = a[i], a[j]

간단하지만 효과적인.


18

다음은 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

지금은 스위치 버전이 좀 더 깔끔해 보입니다.


6
와우, VB에서 완전히 찢어졌습니다. ;-) ( Switch True…)
Konrad Rudolph

@Konrad, 날 이길! :) 이전에 VB6 코드에서이 관용구를 사용해 왔으며 특정 상황에서 가독성에 확실히 도움이 될 수 있습니다.
Mike Spross

'<='는 무엇입니까? '<-'와 관련이 있습니까?
ℝaphink 2009

@Raphink : 작거나 같음.
Paul Ruane

17

유형 스위치 :

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");
}


14

명명 된 결과 매개 변수

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;
}

1
궁금합니다. 다른 언어에도이 기능이 있습니까?
u0b34a0f6ae

1
Matlab에는 비슷한 것이 있습니다.
Dan Lorenc

파스칼은 하나의 값을 반환하기 위해 유사한 구문을 사용합니다.
nes1983

1
@ nes1983 모르는 사람들을 위해 Pascal에서는 고전적으로 함수 이름에 반환 값을 할당합니다.
fuz

FORTRAN은 거의 이것을 가지고 있습니다.
Hut8 2014-06-15

14

에서 제임스 Antill의 대답 :

foo := <-ch     // This blocks.
foo, ok := <-ch // This returns immediately.

또한 잠재적 인 함정 : 수신 및 송신 연산자 의 미묘한 차이 :

a <- ch // sends ch to channel a
<-ch    // reads from channel ch

3
수신 연산자 자체 이제 Go 1.0.3부터 차단 작업입니다. 사양이 수정되었습니다 : golang.org/ref/spec#Receive_operator . 여기에서 차단 동작 (교착 상태)을 시도해보십시오. play.golang.org/p/0yurtWW4Q3
Deleplace

13
/* 
 * 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))
}

4
문제 해결 사이트의 이름과 ID 번호를 제거하는 것이 좋습니다. 질문을 다시 말해보세요. 그 문제에 걸려 넘어지는 사람에게 문제를 망치지 않기 위해서. 또는 그 문제에 대해 인터넷에서 문제를 검색하여 속임수를 쓰려고합니다.
Mizipzor 2009

1
기록을 위해 :이에서 알고리즘 algorithmist.com/index.php/Coin_Change 그것은 "동전의 변화"에 대한 최초의 구글 결과이다가.
György Andrasek 2009

13

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()합니다.


12

채널 반환

이것은 매우 중요한 진정한 관용구입니다. 데이터를 채널에 공급하고 나중에 닫는 방법입니다. 이것으로 간단한 반복자 (범위가 채널을 받아들이 기 때문에) 또는 필터를 만들 수 있습니다.

// 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;
}

+1. 또한 채널을 통해 채널을 전달할 수도 있습니다.
György Andrasek

5
그러나 for x : = range chan {} 루프에서 벗어나지 않도록주의하십시오. 고 루틴과 참조하는 모든 메모리가 누출됩니다.
Jeff Allen

3
@JeffAllen은 고 루틴 defer close(outch);의 첫 번째 진술로 어떻습니까?

1
Defer는 어떤 리턴 포인트를 취하 든 함수가 리턴 될 때 실행할 명령문을 큐에 넣습니다. 그러나 채널 입력이 닫히지 않으면이 예제의 익명 함수는 for 루프를 벗어나지 않습니다.
Jeff Allen

11

채널 읽기 시간 초과 :

ticker := time.NewTicker(ns);
select {
    case v := <- chan_target:
        do_something_with_v;
    case <- ticker.C:
        handle_timeout;
}

Davies Liu 에게서 도난당했습니다 .


11
for {
    v := <-ch
    if closed(ch) {
        break
    }
    fmt.Println(v)
}

범위는 닫힌 채널을 자동으로 확인하므로 다음과 같이 줄일 수 있습니다.

for v := range ch {
    fmt.Println(v)
}

9

$ 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에 추가 할 수 있습니다.


7

Go의 또 다른 흥미로운 점은 godoc. 다음을 사용하여 컴퓨터에서 웹 서버로 실행할 수 있습니다.

godoc -http=:8080

여기서 8080은 포트 번호이고 golang.org의 전체 웹 사이트는에서 사용할 수 있습니다 localhost:8080.


이것은 일반 프로그램입니까 아니면 데몬입니까?
György Andrasek

정규 프로그램입니다.
Jeremy

7

이것은 스택의 구현입니다. 유형에 메소드를 추가하는 방법을 보여줍니다.

나는 조각으로의 스택 부분을 확인하고 조각의 속성을 사용하고 싶어하지만 난없이 작업에 그것을 가지고 있지만 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()
}

10
오히려 사용하는 것보다 fmt.Printf(...); os.Exit();, 당신은 사용할 수 있습니다 panic(...).
notnoop 2009

1
그것은 내가 원하지 않는 스택 추적을 제공합니다.

3
제한되는 이유는 무엇입니까? Go는 관리되는 gc'd 언어입니다. 스택은 원하는만큼 깊을 수 있습니다. 필요에 따라 C의 realloc과 같은 작업을 수행하는 새로운 append () 내장을 사용하십시오.
Jeff Allen

"Go는 제네릭이 필요하지 않습니다"라고 그들은 말했다.
cubuspl42

4

이동에서 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 을 참조하십시오 .


3
정말 "비행 점"을 사용합니까? 감히 편집하지는 않지만 약간 예상치 못한 급진적 인 것 같습니다.
언 와인드

예, 6c (또는 8c 등)로 컴파일해야합니다. gcc가 유니 코드 식별자를 처리한다고 생각하지 않습니다.
Scott Wales

1
AltGr + 마침표 유형이 동일하다고 생각하지만 유니 코드를 사용하면 확실하지 않습니다. 내가 읽은 소스에서 매우 놀랐습니다 .. 왜 :: 같은 것을 사용하지 않습니까?
u0b34a0f6ae

캐릭터는 MIDDLE DOT U + 00B7입니다. 파서는 유효한 c 식별자를 만들기 위해 이것을 문자로 볼 수 있도록 퍼지되었을 수 있습니다.
Scott Wales

4
'·'는 일시적인 해킹 일 뿐이고, Rob은 그것이 아직 거기에 있다는 것에 놀랐습니다. 그는 그것이 덜 특이한 것으로 대체 될 것이라고 말했습니다.
uriel



3

다른 답변을 기반으로하지만 크기 제한이없는 슬라이스 추가를 사용하는 스택입니다.

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()
}

3
const ever = true

for ever {
    // infinite loop
}

25
에헴. for { /* infinite loop */ }충분합니다.
u0b34a0f6ae

2
물론이야. 그게 바로 여기서 일어나는 일입니다. forever키워드가 마음에 들어요 . Qt조차도 그것에 대한 매크로를 가지고 있습니다.
György Andrasek 2009

6
하지만 Go는이 작업을 수행하기 위해 매크로 나 귀여운 true 별칭이 필요하지 않습니다.
u0b34a0f6ae

@ kaizer.se : Jurily의 요점은 for ever(변수를 선언 한 후) 원하는 경우 Go에서 할 수있는 귀여운 것입니다. 영어처럼 보입니다 (공백 모듈로).
Frank

8
그것은 당신이 아니라 C에서 할 수있는 귀여운 뭔가 .. :-)#define ever (;;)
u0b34a0f6ae

2

test메인 디렉토리 에는 작은 프로그램이 많이 있습니다 . 예 :

  • peano.go 계승을 인쇄합니다.
  • hilbert.go 행렬 곱셈이 있습니다.
  • iota.go 이상한 iota의 예가 있습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.