Перейти примеры и идиомы [закрыто]

Не так много кода Go для изучения языка, и я уверен, что я не единственный, кто с ним экспериментирует Итак, если вы узнали что-то интересное о языке, опубликуйте пример здесь.

Я тоже ищу

  • идиоматические способы делать вещи в Go,
  • стиль мышления C /C ++ «портирован» на Go,
  • распространенные ошибки в синтаксисе,
  • что-нибудь интересное, правда.
go
90 голосов | спросил 2 revs, 2 users 100%
György Andrasek
1 Jam1000000amThu, 01 Jan 1970 03:00:00 +030070 1970, 03:00:00

23 ответа


0

Отложенные заявления

  

Оператор "defer" вызывает функцию, выполнение которой откладывается до момента возврата окружающей функции.

     

DeferStmt = "defer" Выражение.

     

Выражение должно быть вызовом функции или метода. Каждый раз, когда выполняется оператор 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);
}

Update:

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)
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Объектные файлы Go содержат заголовок открытого текста:

[email protected] ~/workspace/go/euler31 $ 6g euler31.go
[email protected] ~/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>
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Я видел, как несколько человек жаловались на цикл for в духе «почему мы должны сказать i = 0; i < len; i++ в этот день и возраст? ".

Я не согласен, мне нравится конструкция. Вы можете использовать длинную версию, если хотите, но идиоматическая версия 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:)

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Иди и получи свою репутацию переполнения стека

Это перевод этого ответа .

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

Это выглядит довольно неуклюже, с двумя строками и двумя буферами, поэтому, если у любого специалиста Go есть совет, дайте мне знать.

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Вот хороший пример йоты из сообщения Кинопико :

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 (!)
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Вот идиома со страницы 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;

На данный момент версия коммутатора выглядит для меня чище.

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Вы можете поменять местами переменные путем параллельного присваивания:

x, y = y, x

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

просто, но эффективно.

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Переключатели типов :

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");
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

При импорте пакетов вы можете переопределить имя так, как вам нужно:

package main

import f "fmt"

func main()
{
    f.Printf("Hello World\n");
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Именованные параметры результата

  

Возврат или результат "параметры"   Функция Go может иметь имена и   используется в качестве обычных переменных, так же, как   входящие параметры. Когда названо,   они инициализируются в ноль   значения для их типов, когда   функция начинается; если функция   выполняет оператор возврата без   аргументы, текущие значения   Параметры результата используются в качестве   возвращаемые значения.

     

Имена не обязательны, но они   может сделать код короче и понятнее:   это документация Если мы назовем   результаты nextInt становится очевидным   который вернул int is which.

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;
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0
/* 
 * 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))
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Мне нравится, что вы можете переопределять типы, включая примитивы типа int, столько раз, сколько хотите, и присоединять различные методы. Как определение типа RomanNumeral:

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, " ", 0)
var aRoman = strings.Split(numRoman, " ", 0)

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

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

возврат канала

Это настоящая идиома, которая очень важна: как передавать данные в канал и затем закрывать его. При этом вы можете создавать простые итераторы (так как диапазон будет принимать канал) или фильтры.

// 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;
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0
for {
  v := <-ch;
  if closed(ch) { break }
  fmt.Println(v)
}

Поскольку диапазон автоматически проверяет наличие закрытого канала, мы можем сократить его до этого:

for v := range ch {
  fmt.Println(v)
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Тайм-аут для чтения канала:

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

Украдено у Дэвиса Лю .

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

В системе $ GOROOT /src

есть настройка системы make, которую вы можете использовать

Настройте свой 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, или добавить пакет и общие объекты из cgo в ваш $ GOROOT с помощью make install.

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Это реализация стека. Он иллюстрирует добавление методов к типу.

Я хотел превратить часть стека в срез и использовать свойства среза, но, хотя и получил возможность работать без 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 ();
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Еще одна интересная вещь в Go - это godoc. Вы можете запустить его как веб-сервер на вашем компьютере, используя

godoc -http=:8080

где 8080 - номер порта, и весь сайт golang.org доступен по адресу localhost:8080.

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Вызов кода c с ходу

Можно получить доступ к нижнему уровню go, используя среду выполнения c.

Функции C находятся в форме

void package·function(...)

(обратите внимание, что разделитель точек - это символ Unicode), где аргументы могут быть базовыми типами 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 для примеров, используемых во время выполнения.

См. также этот ответ для связи кода C ++ с перейти.

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Вот пример использования пакета sqlite3.

http://github.com/bikal/gosqlite-example

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Вы смотрели этот доклад ? Он показывает много интересных вещей, которые вы можете сделать (конец выступления)

ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0
const ever = true;

for ever {
    //infinite loop
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24
0

Стек, основанный на другом ответе, но с добавлением фрагмента без ограничения размера.

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()
}
ответил Mujahid khan 27 22018vEurope/Moscow11bEurope/MoscowTue, 27 Nov 2018 10:05:24 +0300 2018, 10:05:24

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132