Golang: анонимная структура и пустая структура

http://play.golang.org/p/vhaKi5uVmm

package main

import "fmt"

var battle = make(chan string)

func warrior(name string, done chan struct{}) {
    select {
    case opponent := <-battle:
        fmt.Printf("%s beat %sn", name, opponent)
    case battle <- name:
        // I lost :-(
    }
    done <- struct{}{}
}

func main() {
    done := make(chan struct{})
    langs := []string{"Go", "C", "C++", "Java", "Perl", "Python"}
    for _, l := range langs { go warrior(l, done) }
    for _ = range langs { <-done }
}

[1. вопрос]

 done <- struct{}{}

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

исходный от Andrew Gerrand по говорить http://nf.wh3rd.net/10things/#10

здесь

 make(chan struct{})

done-это канал типа struct{}

поэтому я попытался с

 done <- struct{}

но это не работает. Зачем мне нужны дополнительные скобки для этой строки?

 done <- struct{}{}

[2. вопрос]

 for _ = range langs { <-done }

зачем мне эта строка? Я знаю, что эта строка необходима, потому что без этой строки нет выхода. Но почему и что это линия делать? И что делает это необходимым в этом коде? Я знаю это <-done принимать значения из канала done и отбрасывать полученные значения. Но зачем мне это делать?

спасибо!

5 ответов


составные литералы

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

struct{}{} является составным литералом типа struct{}, тип значения, за которым следует список со скобками составной элемент.

for _ = range langs { <-done } ждет, пока все goroutines для всех langs отправили done сообщения.


обратите внимание, что одним из интересных аспектов использования struct{} для типа, выталкиваемого в канал (в отличие от int или bool), является то, что в размере пустой структура... 0!

см. недавнюю статью"пустая структура " (март 2014) by Дейв Чейни.

вы можете создать столько struct{} Как вы хотите (struct{}{}), чтобы подтолкнуть их к вашему каналу: Ваша память не будет затронута.
Но вы можете использовать его для сигнализации между go процедуры, как показано в "Любопытный Каналы".

и вы сохраняете все другие преимущества, связанные со структурой:

  • вы можете определить методы на нем (этот тип может быть приемником метода)
  • вы можете реализовать интерфейс (с указанными методами вы просто определяете на своей пустой структуре)
  • as одноэлементный

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

см., например,глобальный var errServerKeyExchange в файле пустой структуры rsaKeyAgreement определяется.


  1. struct{} - Это тип (в частности, структура без элементов). Если у вас есть тип Foo, вы можете создать значение этого типа в выражении с Foo{field values, ...}. Складывая это вместе,struct{}{} является значением типа struct{}, что и ожидает канал.

  2. на main функции появляется warrior горутин, которые будем писать done канал, когда они закончили. Последний for блок считывает с этого канала, сделать main не вернется, пока все горутины закончили. Это важно, потому что программа выйдет, когда main завершает, независимо от того, есть ли другие goroutines работает.


хорошие вопросы,

весь смысл канала структуры в этом сценарии-просто сигнализировать о завершении, что произошло что-то полезное. Тип канала на самом деле не имеет значения, он мог бы использовать int или bool для достижения того же эффекта. Важно то, что его код выполняется синхронно, где он делает необходимую бухгалтерию, чтобы сигнализировать и двигаться дальше в ключевых точках.

Я согласен с синтаксисом struct{}{} сначала выглядит странно потому что в этом примере он объявляет структуру и создает ее в строке, следовательно, второй набор скобок.

Если у вас был ранее существующий объект, например:

type Book struct{

}

вы можете создать его вот так: b := Book{}, вам нужен только один набор скобок, потому что структура книги уже объявлена.


done канал используется для получения уведомлений от warrior метод, который указывает, что работник выполняется обработка. Так что канал может быть любым, например:

func warrior(name string, done chan bool) {
    select {
    case opponent := <-battle:
        fmt.Printf("%s beat %s\n", name, opponent)
    case battle <- name:
        // I lost :-(
    }
    done <- true
}

func main() {
    done := make(chan bool)
    langs := []string{"Go", "C", "C++", "Java", "Perl", "Python"}
    for _, l := range langs { go warrior(l, done) }
    for _ = range langs { <-done }
}

мы объявляем done := make(chan bool) как канал, который получает значение типа bool, и отправить true в конце . Это работает! Вы также можете определить done канал к любому другому типу, это не будет иметь значения.

1. Так что же со странным done <- struct{}{}?

это это просто другой тип, который будет передан на канале. Это пустая структура, если вы знакомы со следующим:

type User struct {
    Name string
    Email string
}

struct{} не имеет значения, за исключением того, что он не содержит полей и struct{}{} это просто пример из него. Лучшая особенность - это не стоит места в памяти!

2. для использования цикла

мы создаем 6 goroutines для работы в фоновом режиме с этой строкой:

    for _, l := range langs { go warrior(l, done) }

мы используем for _ = range langs { <-done }, потому что основной goroutine (где работает основная функция) не ждет goroutins, чтобы закончить.

если мы не включаем последний для строки, скорее всего, мы не видим выходов(потому что основные goroutines завершает работу, прежде чем любой дочерний goroutines выполняет fmt.Printf код, и когда main goroutine завершит работу, все дочерние goroutines уйдут с ним, и у них не будет никаких шансов запустить в любом случае).

поэтому мы ждем, пока все goroutines закончат(он работает до конца и отправляет сообщение к done канала), затем выходит. done канал здесь заблокирован канал, что означает <-done будет блокировать здесь, пока не будет получено сообщение от канала.

у нас есть 6 goroutines в фоновом режиме, и использовать для цикла, мы ждем, пока все goroutines отправить сообщение, которое означает, что он закончил работу (потому что done <-struct{}{} в конце функции).