{"pointers":{"Title":"Ponteiros","Description":"Ponteiros servem ao propósito de compartilhar valores além dos limites do programa.","Pages":[{"Title":"Ponteiros","Content":"\n \u003ch2\u003ePonteiros\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Ponteiros servem ao propósito de compartilhar valores além dos limites do programa.\n\n\n Existem vários tipos de limites do programa. O mais comum é entre chamadas de função.\n\n\n Existe também um limite entre Goroutines que você tem notas para mais tarde.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Passagem por Valor\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Compartilhamento de Dados I\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Compartilhamento de Dados II\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Escape Analysis\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Crescimento da Stack\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n \n \u003cp\u003e\n Quando um programa Go inicia, o Go runtime cria uma Goroutine. Goroutines são\n\n\n threads leves em nível de aplicação com muitas das mesmas semânticas das threads\n\n\n do sistema operacional. O trabalho delas é gerenciar a execução física de um\n\n\n conjunto distinto de instruções. Todo programa Go tem pelo menos 1 Goroutine que\n\n\n você chama de main Goroutine.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Cada Goroutine recebe seu próprio bloco de memória chamado stack. Cada stack começa\n\n\n com uma alocação de 2048 bytes (2k). É muito pequeno, mas stacks podem aumentar\n\n\n de tamanho ao longo do tempo.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/p1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/p1.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Toda vez que uma função é chamada, um bloco de espaço da stack é ocupado para ajudar a\n\n\n Goroutine a executar as instruções associadas a essa função. Cada bloco individual de\n\n\n memória é chamado de frame.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O tamanho de um frame para uma determinada função é calculado em tempo de compilação.\n\n\n Nenhum valor pode ser construído na stack sem que o compilador saiba o tamanho desse \n\n\n valor em tempo de compilação. Se o compilador não sabe o tamanho do valor em tempo\n\n\n de compilação, o valor tem que ser construído na heap.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Stacks são autolimpantes e zero values ajudam na inicialização da stack.\n\n\n Toda vez que uma função é chamada, e um frame de memória é bloqueado, a memória\n\n\n desse frame é inicializada, e é assim que a stack se limpa. No retorno de uma\n\n\n função, a memória do frame é deixada de lado, pois não se sabe se essa memória\n\n\n será necessária novamente. Seria ineficiente inicializar a memória nos retornos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003ePassagem\u003c/b\u003e \u003cb\u003ePor\u003c/b\u003e \u003cb\u003eValor\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Todos os dados são movidos pelo programa por valor. Isso significa que à medida\n\n\n que os dados são transmitidos através dos limites do programa, cada função ou Goroutine\n\n\n recebe sua própria cópia dos dados. Existem dois tipos de dados com os quais você\n\n\n trabalhará, o valor em si (int, string, user) ou o endereço do valor. Endereços são os\n\n\n dados que precisam ser copiados e armazenados além dos limites do programa.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O código a seguir tenta explicar isso melhor.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n\n // Declare variable of type int with a value of 10.\n count := 10\n\n // To get the address of a value, use the \u0026amp; operator.\n println(\u0026#34;count:\\tValue Of[\u0026#34;, count, \u0026#34;]\\tAddr Of[\u0026#34;, \u0026amp;count, \u0026#34;]\u0026#34;)\n\n // Pass a copy of the \u0026#34;value of\u0026#34; count (what’s in the box)\n // to the increment1 function.\n increment1(count)\n\n // Print out the \u0026#34;value of\u0026#34; and \u0026#34;address of\u0026#34; count.\n // The value of count will not change after the function call.\n println(\u0026#34;count:\\tValue Of[\u0026#34;, count, \u0026#34;]\\tAddr Of[\u0026#34;, \u0026amp;count, \u0026#34;]\u0026#34;)\n\n // Pass a copy of the \u0026#34;address of\u0026#34; count (where is the box)\n // to the increment2 function. This is still considered a pass by\n // value and not a pass by reference because addresses are values.\n increment2(\u0026amp;count)\n\n // Print out the \u0026#34;value of\u0026#34; and \u0026#34;address of\u0026#34; count.\n // The value of count has changed after the function call.\n println(\n \u0026#34;count:\\tValue Of[\u0026#34;, \n count, \u0026#34;]\\tAddr Of[\u0026#34;, \u0026amp;count, \u0026#34;]\u0026#34;)\n}\n\n// increment1 declares the function to accept its own copy of\n// and integer value.\nfunc increment1(inc int) {\n\n // Increment the local copy of the caller’s int value.\n inc\u0026#43;\u0026#43;\n println(\u0026#34;inc1:\\tValue Of[\u0026#34;, inc, \u0026#34;]\\tAddr Of[\u0026#34;, \u0026amp;inc, \u0026#34;]\u0026#34;)\n}\n\n// increment2 declares the function to accept its own copy of\n// an address that points to an integer value.\n// Pointer variables are literal types and are declared using *.\nfunc increment2(inc *int) {\n\n // Increment the caller’s int value through the pointer.\n *inc\u0026#43;\u0026#43;\n println(\n \u0026#34;inc2:\\tValue Of[\u0026#34;, \n inc, \u0026#34;]\\tAddr Of[\u0026#34;, \u0026amp;inc, \n \u0026#34;]\\tPoints To[\u0026#34;, *inc, \u0026#34;]\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ecount: Value Of[ 10 ] Addr Of[ 0xc000050738 ]\ninc1: Value Of[ 11 ] Addr Of[ 0xc000050730 ]\ncount: Value Of[ 10 ] Addr Of[ 0xc000050738 ]\ninc2: Value Of[ 0xc000050738 ] Addr Of[ 0xc000050748 ] Points To[ 11 ]\ncount: Value Of[ 11 ] Addr Of[ 0xc000050738 ]\u003c/pre\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eUse ponteiros para compartilhar dados.\u003c/li\u003e\n \n \u003cli\u003eValores em Go são sempre passados por valor.\u003c/li\u003e\n \n \u003cli\u003e\u0026#34;Value of\u0026#34; é o que está na caixa. \u0026#34;Address of\u0026#34; ( \u0026amp; ) é onde está a caixa.\u003c/li\u003e\n \n \u003cli\u003eO operador ( * ) declara uma variável de ponteiro e o \u0026#34;Valor para o qual o ponteiro aponta\u0026#34;.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eEscape Analysis\u003c/h2\u003e\n \n \n \u003cp\u003e\n O algoritmo que o compilador usa para determinar se um valor deve ser construído\n\n\n na stack ou na heap é chamado \u0026#34;escape analysis\u0026#34;. O nome do algoritmo faz parecer\n\n\n que os valores são construídos primeiro na stack e então escapam (ou são movidos)\n\n\n para a heap, quando necessário. Este NÃO é o caso. A construção de um valor ocorre\n\n\n apenas uma vez, e o algoritmo de escape analysis decide onde ele ficará (stack or\n\n\n heap). Somente a construção na heap é chamada de alocação em Go.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Compreender escape analysis é sobre compreender quem é o dono de cada valor. A ideia é\n\n\n que, quando um valor é construído dentro do escopo de uma função, então essa função é\n\n\n dona deste valor. A partir daí, pergunte: o valor que está sendo construído ainda\n\n\n precisa existir quando a função retornar? Se a resposta for não, o valor pode ser\n\n\n construído na stack. Se a resposta for sim, o valor deverá ser construído na heap.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nota: A regra de propriedade é uma boa regra básica para identificar códigos\n\n\n que causam alocações. Entretanto, você deve compreender que a escape analysis\n\n\n tem falhas que podem resultar em alocações não óbvias. Além disso, o algoritmo\n\n\n aproveita oportunidades para utilizar as otimizações do compilador para economizar\n\n\n nas alocações.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// user represents a user in the system.\ntype user struct {\n name string\n email string\n}\n\nfunc stayOnStack() user {\n u := user{\n name: \u0026#34;Bill\u0026#34;,\n email: \u0026#34;bill@email.com\u0026#34;,\n }\n\n return u\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função stayOnStack está utilizando semântica de valor para retornar um valor de\n\n\n user para quem a chamou. Em outras palavras, quem chamou a função \n\n\n recebe sua própria cópia do valor do user que está sendo construído.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando a função stayOnStack é chamada e retorna, o valor do user que ela constrói\n\n\n não precisa mais existir, pois quem a chamou está obtendo sua própria cópia.\n\n\n Portanto, a construção do valor do user dentro de stayOnStack pode acontecer na stack.\n\n\n Sem alocação.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n email string\n}\n\nfunc escapeToHeap() *user {\n u := user{\n name: \u0026#34;Bill\u0026#34;,\n email: \u0026#34;bill@email.com\u0026#34;,\n }\n\n return \u0026amp;u\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função escapeToHeap está utilizando semântica de ponteiro para retornar um valor\n\n\n de user para quem a chamou. Em outras palavras, quem chamou a função obtém acesso\n\n\n (um endereço) ao valor do user sendo construído.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando a função escapeToHeap é chamada e retorna, o valor do user que ela constrói\n\n\n ainda precisa existir, pois quem a chamou está obtendo acesso compartilhado ao valor.\n\n\n Portanto, a construção do valor do user dentro de escapeToHeap não pode acontecer\n\n\n na stack, deve acontecer na heap. Com alocação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Pense no que aconteceria se o valor do user no último exemplo fosse construído\n\n\n na stack ao utilizar a semântica de ponteiro no retorno.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/p2.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/p2.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Quem chamou a função teria uma cópia de um endereço da stack do frame abaixo e a\n\n\n integridade seria perdida. Uma vez que o controle volta para a função que está chamando,\n\n\n a memória na stack onde o valor do user existe é novamente reutilizável. No momento\n\n\n em que a função chamadora faz outra chamada de função, um novo frame é fatiado e\n\n\n a memória será sobrescrita, destruindo o valor compartilhado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n É por isso que você pensa que a stack é autolimpante. A inicialização com o zero value\n\n\n ajuda a limpar cada frame da stack sem o uso do GC. A stack é autolimpante, pois um\n\n\n frame é obtido e inicializado para cada chamada de função. A stack é limpa durante as\n\n\n chamadas de função e não nos retornos, porque o compilador não sabe se a memória na\n\n\n stack será necessária novamente.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A escape analysis decide se um valor é construído na stack (por padrão) ou na heap\n\n\n (o escape). Na função stayOnStack, eu estou passando uma cópia do valor de volta\n\n\n para o chamador, portanto é seguro manter o valor na stack. Na função escapeToHeap,\n\n\n eu estou passando uma cópia do endereço do valor de volta para o chamador (compartilhando\n\n\n a stack), portanto, não é seguro manter o valor na stack.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Existem vários pequenos detalhes relacionados à escape analysis, então para saber\n\n\n mais leia o post no capítulo 14 chamado Mecânicas da Escape Analysis.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nota: A partir da versão 1.17, Go mudou a ABI (application binary interface) para\n\n\n implementar uma nova maneira de passar argumentos de entrada e saída de função\n\n\n usando registradores em vez de memória na stack. Isso está habilitado para Linux,\n\n\n MacOS, e Windows nas arquiteturas x86 de 64 bits. Isso significa que alguns argumentos\n\n\n de função não serão copiados na stack, mas alguns serão, dependendo da viabilidade\n\n\n do uso de registradores. Isso não altera nenhuma das semânticas descritas neste capítulo.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eQuando um valor pode ser referenciado após o retorno da função que o constrói.\u003c/li\u003e\n \n \u003cli\u003eQuando o compilador determina que um valor é grande demais para caber na stack.\u003c/li\u003e\n \n \u003cli\u003eQuando o compilador não sabe o tamanho de um valor em tempo de compilação.\u003c/li\u003e\n \n \u003cli\u003eQuando um valor é desacoplado por meio do uso de valores de função ou interface.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eSemânticas de Garbage Collection\u003c/h2\u003e\n \n \n \u003cp\u003e\n Uma vez que um valor é construído na heap, o Garbage Collector (GC) precisa se\n\n\n envolver. A parte mais importante do GC é o algoritmo de frequência. Ele determina\n\n\n a frequência/ritmo que o GC deve executar para manter a menor heap possível em\n\n\n conjunto com o melhor throughput da aplicação.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2018/12/garbage-collection-in-go-part1-semantics.html\" target=\"_blank\"\u003eGarbage Collection Semantics Part I\u003c/a\u003e - William Kennedy\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eStack vs Heap\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u0026#34;A stack é para dados que precisam persistir apenas durante o tempo de vida da função\n\n\n que os constrói, e é recuperada sem nenhum custo quando a função é encerrada. A heap\n\n\n é para dados que precisam persistir após o encerramento da função que os constrói, e\n\n\n é recuperada por uma garbage collection às vezes cara.\u0026#34; - Ayan George\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eCrescimento da Stack\u003c/h2\u003e\n \n \n \u003cp\u003e\n O tamanho de cada frame para cada função é calculado em tempo de compilação. Isso significa que,\n\n\n se o compilador não souber o tamanho de um valor em tempo de compilação, o valor deve ser\n\n\n construído na heap. Um exemplo disso é usar a função built-in make para construir uma\n\n\n slice cujo tamanho é baseado em uma variável.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eb := make([]byte, size) // Backing array allocates on the heap.\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Go usa uma implementação de stack contígua para determinar como as stacks crescem\n\n\n e diminuem.\n\n\n Uma alternativa que Go poderia ter usado é uma implementação de stack segmentada,\n\n\n que é utilizada por alguns sistemas operacionais.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Toda chamada de função vem com um pequeno preâmbulo que pergunta: \u0026#34;Existe espaço\n\n\n de stack suficiente para este novo frame?\u0026#34;. Se sim, não há problema e o frame é\n\n\n obtido e inicializado. Se não, uma nova stack maior deverá ser construída e a memória\n\n\n da stack existente deverá ser copiada para a nova. Isso requer mudanças de ponteiros\n\n\n que fazem referência à memória na stack. Os benefícios da memória contígua e\n\n\n das travessias lineares com hardware moderno é o tradeoff pelo custo da cópia.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Devido ao uso de stacks contíguas, nenhuma Goroutine pode ter um ponteiro apontando\n\n\n para a stack de outra Goroutine. Haveria muita sobrecarga no runtime para acompanhar\n\n\n cada ponteiro para cada stack e reajustar esses ponteiros para a nova localização.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003e Mecânica\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003ePonteiros\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/doc/effective_go.html#pointers_vs_values\" target=\"_blank\"\u003ePointers vs. Values\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2017/05/language-mechanics-on-stacks-and-pointers.html\" target=\"_blank\"\u003eLanguage Mechanics On Stacks And Pointers\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/12/using-pointers-in-go.html\" target=\"_blank\"\u003eUsing Pointers In Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/07/understanding-pointers-and-memory.html\" target=\"_blank\"\u003eUnderstanding Pointers and Memory Allocation\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eStacks\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzWtrZFQ5suE8qr2sD8uWQ/pub\" target=\"_blank\"\u003eContiguous Stack Proposal\u003c/a\u003e \u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eEscape\u003c/b\u003e \u003cb\u003eAnalysis\u003c/b\u003e \u003cb\u003ee\u003c/b\u003e \u003cb\u003eInlining\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://docs.google.com/document/d/1CxgUBPlx9iJzkz9JWkb6tIpTe5q32QDmz8l0BouG0Cw\" target=\"_blank\"\u003eGo Escape Analysis Flaws\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/golang/go/wiki/CompilerOptimizations\" target=\"_blank\"\u003eCompiler Optimizations\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eGarbage\u003c/b\u003e \u003cb\u003eCollection\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"http://gchandbook.org/\" target=\"_blank\"\u003eThe Garbage Collection Handbook\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/golang/proposal/blob/master/design/44167-gc-pacer-redesign.md\" target=\"_blank\"\u003eGC Pacer Redesign - 2021\u003c/a\u003e - Michael Knyszek \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Tracing_garbage_collection\" target=\"_blank\"\u003eTracing Garbage Collection\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/go15gc\" target=\"_blank\"\u003eGo Blog - 1.5 GC\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=aiv1JOfMjm0\u0026amp;index=16\u0026amp;list=PL2ntRZ1ySWBf-_z-gHCOR2N156Nw930Hm\" target=\"_blank\"\u003eGo GC: Solving the Latency Problem\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://rubinius.com/2013/06/22/concurrent-garbage-collection\" target=\"_blank\"\u003eConcurrent garbage collection\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://docs.google.com/document/d/1wmjrocXIWTr1JxU-3EQBI6BK6KgtiFArkG47XK73xIQ/edit\" target=\"_blank\"\u003eGo 1.5 concurrent garbage collector pacing\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/golang/proposal/blob/master/design/17503-eliminate-rescan.md\" target=\"_blank\"\u003eEliminating Stack Re-Scanning\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://groups.google.com/forum/m/#!topic/golang-nuts/KJiyv2mV2pU\" target=\"_blank\"\u003eWhy golang garbage-collector not implement Generational and Compact gc?\u003c/a\u003e - Ian Lance Taylor \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/ismmkeynote\" target=\"_blank\"\u003eGetting to Go: The Journey of Go\u0026#39;s Garbage Collector\u003c/a\u003e - Rick Hudson \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2018/12/garbage-collection-in-go-part1-semantics.html\" target=\"_blank\"\u003eGarbage Collection In Go : Part I - Semantics\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2019/05/garbage-collection-in-go-part2-gctraces.html\" target=\"_blank\"\u003eGarbage Collection In Go : Part II - GC Traces\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2019/07/garbage-collection-in-go-part3-gcpacing.html\" target=\"_blank\"\u003eGarbage Collection In Go : Part III - GC Pacing\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i-learnt-to-stop-worrying-and-love-the-heap-26c2462549a2/\" target=\"_blank\"\u003eGo memory ballast: How I learnt to stop worrying and love the heap\u003c/a\u003e - Ross Engers \u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eOtimizações\u003c/b\u003e \u003cb\u003eEstáticas\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003eAtribuição\u003c/b\u003e \u003cb\u003eÚnica\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=D2-gaMvWfQY\" target=\"_blank\"\u003eGopherCon 2015: Ben Johnson - Static Code Analysis Using SSA\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://godoc.org/golang.org/x/tools/go/ssa\" target=\"_blank\"\u003ePackage SSA\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=FnGCDLhaxKU\" target=\"_blank\"\u003eUnderstanding Compiler Optimization\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show the basic concept of pass by value.\npackage main\n\nfunc main() {\n\n\t// Declare variable of type int with a value of 10.\n\tcount := 10\n\n\t// Display the \"value of\" and \"address of\" count.\n\tprintln(\"count:\\tValue Of[\", count, \"]\\tAddr Of[\", \u0026count, \"]\")\n\n\t// Pass the \"value of\" the count.\n\tincrement(count)\n\n\tprintln(\"count:\\tValue Of[\", count, \"]\\tAddr Of[\", \u0026count, \"]\")\n}\n\n// increment declares count as a pointer variable whose value is\n// always an address and points to values of type int.\n//\n//go:noinline\nfunc increment(inc int) {\n\n\t// Increment the \"value of\" inc.\n\tinc++\n\tprintln(\"inc:\\tValue Of[\", inc, \"]\\tAddr Of[\", \u0026inc, \"]\")\n}\n","Hash":"pOmUh0KFKfsBDVKYeDM0vX9f3r0="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show the basic concept of using a pointer\n// to share data.\npackage main\n\nfunc main() {\n\n\t// Declare variable of type int with a value of 10.\n\tcount := 10\n\n\t// Display the \"value of\" and \"address of\" count.\n\tprintln(\"count:\\tValue Of[\", count, \"]\\t\\tAddr Of[\", \u0026count, \"]\")\n\n\t// Pass the \"address of\" count.\n\tincrement(\u0026count)\n\n\tprintln(\"count:\\tValue Of[\", count, \"]\\t\\tAddr Of[\", \u0026count, \"]\")\n}\n\n// increment declares count as a pointer variable whose value is\n// always an address and points to values of type int.\n//\n//go:noinline\nfunc increment(inc *int) {\n\n\t// Increment the \"value of\" count that the \"pointer points to\".\n\t*inc++\n\n\tprintln(\"inc:\\tValue Of[\", inc, \"]\\tAddr Of[\", \u0026inc, \"]\\tValue Points To[\", *inc, \"]\")\n}\n","Hash":"SkbfO370ljcCFrP1cKDb+FuFBws="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show the basic concept of using a pointer\n// to share data.\npackage main\n\nimport \"fmt\"\n\n// user represents a user in the system.\ntype user struct {\n\tname string\n\temail string\n\tlogins int\n}\n\nfunc main() {\n\n\t// Declare and initialize a variable named bill of type user.\n\tbill := user{\n\t\tname: \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\t//** We don't need to include all the fields when specifying field\n\t// names with a struct literal.\n\n\t// Pass the \"address of\" the bill value.\n\tdisplay(\u0026bill)\n\n\t// Pass the \"address of\" the logins field from within the bill value.\n\tincrement(\u0026bill.logins)\n\n\t// Pass the \"address of\" the bill value.\n\tdisplay(\u0026bill)\n}\n\n// increment declares logins as a pointer variable whose value is\n// always an address and points to values of type int.\nfunc increment(logins *int) {\n\t*logins++\n\tfmt.Printf(\"\u0026logins[%p] logins[%p] *logins[%d]\\n\\n\", \u0026logins, logins, *logins)\n}\n\n// display declares u as user pointer variable whose value is always an address\n// and points to values of type user.\nfunc display(u *user) {\n\tfmt.Printf(\"%p\\t%+v\\n\", u, *u)\n\tfmt.Printf(\"Name: %q Email: %q Logins: %d\\n\\n\", u.name, u.email, u.logins)\n}\n","Hash":"Jg2hSWEYmnWWIw8PvC2eTX9Fc4A="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to teach the mechanics of escape analysis.\npackage main\n\n// user represents a user in the system.\ntype user struct {\n\tname string\n\temail string\n}\n\n// main is the entry point for the application.\nfunc main() {\n\tu1 := createUserV1()\n\tu2 := createUserV2()\n\n\tprintln(\"u1\", \u0026u1, \"u2\", u2)\n}\n\n// createUserV1 creates a user value and passed\n// a copy back to the caller.\n//\n//go:noinline\nfunc createUserV1() user {\n\tu := user{\n\t\tname: \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\tprintln(\"V1\", \u0026u)\n\n\treturn u\n}\n\n// createUserV2 creates a user value and shares\n// the value with the caller.\n//\n//go:noinline\nfunc createUserV2() *user {\n\tu := user{\n\t\tname: \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\tprintln(\"V2\", \u0026u)\n\n\treturn \u0026u\n}\n\n/*\n// See escape analysis and inlining decisions.\n\n$ go build -gcflags -m=2\n# github.com/ardanlabs/gotraining/topics/go/language/pointers/example4\n./example4.go:24:6: cannot inline createUserV1: marked go:noinline\n./example4.go:38:6: cannot inline createUserV2: marked go:noinline\n./example4.go:14:6: cannot inline main: function too complex: cost 132 exceeds budget 80\n./example4.go:39:2: u escapes to heap:\n./example4.go:39:2: flow: ~r0 = \u0026u:\n./example4.go:39:2: from \u0026u (address-of) at ./example4.go:46:9\n./example4.go:39:2: from return \u0026u (return) at ./example4.go:46:2\n./example4.go:39:2: moved to heap: u\n\n// See the intermediate representation phase before\n// generating the actual arch-specific assembly.\n\n$ go build -gcflags -S\nCALL\t\"\".createUserV1(SB)\n\t0x0026 00038 MOVQ\t(SP), AX\n\t0x002a 00042 MOVQ\t8(SP), CX\n\t0x002f 00047 MOVQ\t16(SP), DX\n\t0x0034 00052 MOVQ\t24(SP), BX\n\t0x0039 00057 MOVQ\tAX, \"\".u1+40(SP)\n\t0x003e 00062 MOVQ\tCX, \"\".u1+48(SP)\n\t0x0043 00067 MOVQ\tDX, \"\".u1+56(SP)\n\t0x0048 00072 MOVQ\tBX, \"\".u1+64(SP)\n\t0x004d 00077 PCDATA\t$1,\n\n// See bounds checking decisions.\n\ngo build -gcflags=\"-d=ssa/check_bce/debug=1\"\n\n// See the actual machine representation by using\n// the disassembler.\n\n$ go tool objdump -s main.main example4\nTEXT main.main(SB) github.com/ardanlabs/gotraining/topics/go/language/pointers/example4/example4.go\n example4.go:15\t0x105e281\t\te8ba000000\t\tCALL main.createUserV1(SB)\n example4.go:15\t0x105e286\t\t488b0424\t\tMOVQ 0(SP), AX\n example4.go:15\t0x105e28a\t\t488b4c2408\t\tMOVQ 0x8(SP), CX\n example4.go:15\t0x105e28f\t\t488b542410\t\tMOVQ 0x10(SP), DX\n example4.go:15\t0x105e294\t\t488b5c2418\t\tMOVQ 0x18(SP), BX\n example4.go:15\t0x105e299\t\t4889442428\t\tMOVQ AX, 0x28(SP)\n example4.go:15\t0x105e29e\t\t48894c2430\t\tMOVQ CX, 0x30(SP)\n example4.go:15\t0x105e2a3\t\t4889542438\t\tMOVQ DX, 0x38(SP)\n example4.go:15\t0x105e2a8\t\t48895c2440\t\tMOVQ BX, 0x40(SP)\n\n// See a list of the symbols in an artifact with\n// annotations and size.\n\n$ go tool nm example4\n 105e340 T main.createUserV1\n 105e420 T main.createUserV2\n 105e260 T main.main\n 10cb230 B os.executablePath\n*/\n","Hash":"UomTM68Rpo2lG0Gq6ecuOpbMvmI="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how stacks grow/change.\npackage main\n\n// Number of elements to grow each stack frame.\n// Run with 1 and then with 1024\nconst size = 1\n\n// main is the entry point for the application.\nfunc main() {\n\ts := \"HELLO\"\n\tstackCopy(\u0026s, 0, [size]int{})\n}\n\n// stackCopy recursively runs increasing the size\n// of the stack.\n//\n//go:noinline\nfunc stackCopy(s *string, c int, a [size]int) {\n\tprintln(c, s, *s)\n\n\tc++\n\tif c == 10 {\n\t\treturn\n\t}\n\n\tstackCopy(s, c, a)\n}\n","Hash":"5ZB6rugKkwoMKkGLMDTUZr8DskY="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo como ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Declare e inicialize uma variável do tipo int com o valor 20.\n\n\n Exiba o \u0026#34;address of\u0026#34; e \u0026#34;value of\u0026#34; da variável.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Declare e inicialize um ponteiro de int que aponta para a\n\n\n última variável que você acabou de criar. Exiba o \u0026#34;address of\u0026#34;, \u0026#34;value of\u0026#34; e o\n\n\n \u0026#34;valor para o qual o ponteiro aponta\u0026#34;.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eExercício 2\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declare um tipo struct e crie um valor desse tipo. Declare uma função que\n\n\n pode mudar o valor de algum campo desse tipo struct. Exiba o valor antes\n\n\n e depois de chamar a função.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare and initialize a variable of type int with the value of 20. Display\n// the _address of_ and _value of_ the variable.\n//\n// Declare and initialize a pointer variable of type int that points to the last\n// variable you just created. Display the _address of_ , _value of_ and the\n// _value that the pointer points to_.\npackage main\n\n// Add imports.\n\nfunc main() {\n\n\t// Declare an integer variable with the value of 20.\n\n\t// Display the address of and value of the variable.\n\n\t// Declare a pointer variable of type int. Assign the\n\t// address of the integer variable above.\n\n\t// Display the address of, value of and the value the pointer\n\t// points to.\n}\n","Hash":"UT45taFQNRGna7ZDM3ZqplW03ag="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare and initialize a variable of type int with the value of 20. Display\n// the _address of_ and _value of_ the variable.\n//\n// Declare and initialize a pointer variable of type int that points to the last\n// variable you just created. Display the _address of_ , _value of_ and the\n// _value that the pointer points to_.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare an integer variable with the value of 20.\n\tvalue := 20\n\n\t// Display the address of and value of the variable.\n\tfmt.Println(\"Address Of:\", \u0026value, \"Value Of:\", value)\n\n\t// Declare a pointer variable of type int. Assign the\n\t// address of the integer variable above.\n\tp := \u0026value\n\n\t// Display the address of, value of and the value the pointer\n\t// points to.\n\tfmt.Println(\"Address Of:\", \u0026p, \"Value Of:\", p, \"Points To:\", *p)\n}\n","Hash":"C/e/8szXy5mAJI97cMHz8SiyNHY="},{"Name":"exercise2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct type and create a value of this type. Declare a function\n// that can change the value of some field in this struct type. Display the\n// value before and after the call to your function.\npackage main\n\n// Add imports.\n\n// Declare a type named user.\n\n// Create a function that changes the value of one of the user fields.\nfunc funcName( /* add pointer parameter, add value parameter */ ) {\n\n\t// Use the pointer to change the value that the\n\t// pointer points to.\n}\n\nfunc main() {\n\n\t// Create a variable of type user and initialize each field.\n\n\t// Display the value of the variable.\n\n\t// Share the variable with the function you declared above.\n\n\t// Display the value of the variable.\n}\n","Hash":"wURH8iUHD31yzXxDygZf6QOTCPM="},{"Name":"answer2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct type and create a value of this type. Declare a function\n// that can change the value of some field in this struct type. Display the\n// value before and after the call to your function.\npackage main\n\nimport \"fmt\"\n\n// user represents a user in the system.\ntype user struct {\n\tname string\n\temail string\n\taccessLevel int\n}\n\nfunc main() {\n\n\t// Create a variable of type user and initialize each field.\n\tbill := user{\n\t\tname: \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t\taccessLevel: 1,\n\t}\n\n\t// Display the value of the accessLevel field.\n\tfmt.Println(\"access:\", bill.accessLevel)\n\n\t// Share the bill variable with the accessLevel function\n\t// along with a value to update the accessLevel field with.\n\taccessLevel(\u0026bill, 10)\n\n\t// Display the value of the accessLevel field again.\n\tfmt.Println(\"access:\", bill.accessLevel)\n}\n\n// accessLevel changes the value of the users access level.\nfunc accessLevel(u *user, accessLevel int) {\n\n\t// Set of value of the accessLevel field to the value\n\t// that is passed in.\n\tu.accessLevel = accessLevel\n}\n","Hash":"idovziRTg7za0YuFVNUvJWvArVI="}]}]} ,"struct-types":{"Title":"Tipos estruturados (Structs)","Description":"Os tipos estruturados são uma forma de criar tipos complexos que agrupam campos de dados juntos.","Pages":[{"Title":"Tipos estruturados","Content":"\n \u003ch2\u003eTipos estruturados\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira? Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Os tipos estruturados são uma maneira de criar tipos complexos que agrupam diferentes campos de dados. \n\n\n Eles são ótimos para organizar e compartilhar diferentes aspectos dos dados que seu programa consome.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A potencial performance da arquitetura de um computador é predominantemente determinada pelo comprimento \n\n\n da palavra (o número de bits que podem ser processados por acesso) e, mais importante, pelo tamanho da memória, \n\n\n ou o número de palavras que pode acessar.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declare, crie e inicialize tipos estruturados.\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Tipos estruturados anônimos.\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Tipos nomeados vs não nomeados. \u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Alinhamento de tipos estruturados\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eStruct e mecanismos de construção\u003c/h2\u003e\n \n \n \u003cp\u003e\n A declaração abaixo representa um tipo definido pelo usuário \n\n\n como um composto de diferentes campos e tipos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype example struct {\n flag bool\n counter int16\n pi float32\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Declare uma variável do tipo exemplo e inicialize-a para o seu valor inicial padrão.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar e1 example\n\nfmt.Printf(\u0026#34;%\u0026#43;v\\n\u0026#34;, e1)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e{flag:false counter:0 pi:0}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Declare uma variável do tipo example, não configurada para seu estado de valor inicial padrão, \n\n\n usando a sintaxe de construção literal.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ee2 := example{\n flag: true,\n counter: 10,\n pi: 3.141592,\n}\n\nfmt.Println(\u0026#34;Flag\u0026#34;, e2.flag)\nfmt.Println(\u0026#34;Counter\u0026#34;, e2.counter)\nfmt.Println(\u0026#34;Pi\u0026#34;, e2.pi)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eFlag true\nCounter 10\nPi 3.141592\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Declare uma variável de um tipo literal anônimo configurado para seu estado de valor não-zero \n\n\n usando a sintaxe de construção literal.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ee3 := struct {\n flag bool\n counter int16\n pi float32\n}{\n flag: true,\n counter: 10,\n pi: 3.141592,\n}\n\nfmt.Println(\u0026#34;Flag\u0026#34;, e3.flag)\nfmt.Println(\u0026#34;Counter\u0026#34;, e3.counter)\nfmt.Println(\u0026#34;Pi\u0026#34;, e3.pi)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eFlag true\nCounter 10\nPi 3.141592\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A ideia de construção literal é justamente essa, construir algo literalmente sem um nome.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você deve usar var para o valor inicial padrão e o operador de declaração de variável curta com a sintaxe \n\n\n { } para construção de valor não-zero.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003ePadding e Alinhamento\u003c/h2\u003e\n \n \n \u003cp\u003e\n Quanto de memória é alocado para um valor do tipo example?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype example struct {\n flag bool\n counter int16\n pi float32\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Um bool é 1 byte, int16 é 2 bytes, e float32 é 4 bytes. Some tudo e você obtém 7 bytes. \n\n\n No entanto, a resposta real é 8 bytes. \n\n\n Por quê? Porque há um byte de preenchimento (padding) entre os campos flag e counter por causa do alinhamento.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/f1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/f1.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n A ideia de alinhamento é permitir que o hardware leia a memória de maneira mais eficiente, colocando a memória em limites de alinhamento específicos. \n\n\n O compilador cuida da mecânica dos limites de alinhamento, então você não precisa se preocupar com isso.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Dependendo do tamanho de um campo particular e de seu posicionamento na struct, \n\n\n Go determina o preenchimento (padding) necessário.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype example2 struct {\n flag bool\n counter int16\n flag2 bool\n pi float32\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste exemplo, eu adicionei um novo campo chamado flag2 entre os campos counter e pi. \n\n\n Isso causa mais preenchimento (padding) dentro da struct.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype example2 struct {\n flag bool // 0xc000100020 \u0026lt;- Endereço inicial\n byte // 0xc000100021 \u0026lt;- 1 byte de padding\n counter int16 // 0xc000100022 \u0026lt;- 2 byte de alinhamento\n flag2 bool // 0xc000100024 \u0026lt;- 1 byte de alinhamento\n byte // 0xc000100025 \u0026lt;- 1 byte de padding\n byte // 0xc000100026 \u0026lt;- 1 byte de padding\n byte // 0xc000100027 \u0026lt;- 1 byte de padding\n pi float32 // 0xc000100028 \u0026lt;- 4 byte de alinhamento\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n É assim que o alinhamento e o preenchimento (padding) ocorrem se um valor do tipo example2 começa no endereço 0xc000100020. \n\n\n O campo flag representa o endereço inicial e tem apenas 1 byte de tamanho. Como o campo counter requer 2 bytes de alocação, \n\n\n ele deve ser colocado na memória com um alinhamento de 2 bytes, significando que precisa estar em um endereço que seja múltiplo de 2. \n\n\n Isso faz com que o campo counter comece no endereço 0xc000100022. Isso cria um espaço de 1 byte entre os campos flag e counter.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/f2.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/f2.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n O campo \u003ccode\u003eflag2\u003c/code\u003e é um bool e pode ficar no próximo endereço 0xc000100024. O campo final é pi e requer 4 bytes de alocação, \n\n\n então ele precisa estar em um alinhamento de 4 bytes. O próximo endereço para um valor de 4 bytes está em 0xc000100028. \n\n\n Isso significa que são necessários mais 3 bytes de preenchimento para manter um alinhamento adequado. \n\n\n Isso resulta em um valor do tipo example2 necessitando de 12 bytes de alocação de memória total.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O maior campo em um struct representa o limite de alinhamento para o struct inteiro. \n\n\n Neste caso, o maior campo é de 4 bytes, então o endereço inicial para este valor de struct deve ser múltiplo de 4. \n\n\n Você pode ver que o endereço 0xc000100020 é um múltiplo de 4.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se você precisa minimizar a quantidade de bytes de preenchimento, você deve organizar os campos de maior alocação para a menor alocação. \n\n\n Isso irá empurrar qualquer byte de preenchimento necessário para a parte inferior do struct e reduzir o número total de bytes de preenchimento necessário.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype example struct {\n pi float32 // 0xc000100020 \u0026lt;- Endereço inicial\n counter int16 // 0xc000100024 \u0026lt;- 2 bytes de alinhamento\n flag bool // 0xc000100026 \u0026lt;- 1 byte de alinhamento\n flag2 bool // 0xc000100027 \u0026lt;- 1 byte de alinhamento\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após a reorganização dos campos, o valor do struct requer apenas 8 bytes de alocação, e não 12 bytes. \n\n\n Uma vez que todos os campos permitem que o valor do struct esteja em um \n\n\n alinhamento de 4 bytes, nenhum byte de preenchimento extra é necessário.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/f3.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/f3.png\"\u003e\n \u003c/a\u003e\n\n\n \u003ch2\u003eAtribuindo Valores\u003c/h2\u003e\n \n \n \u003cp\u003e\n Se você tem dois tipos nomeados diferentes que são idênticos em estrutura, você não pode atribuir \n\n\n um valor de um ao outro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Por exemplo, se os tipos example1 e example2 são declarados usando a mesma \n\n\n declaração exata e inicializamos duas variáveis.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar ex1 example1\nvar ex2 example2\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você não pode atribuir essas duas variáveis uma à outra, já que são de tipos nomeados diferentes. \n\n\n O fato de elas serem idênticas em estrutura é irrelevante.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eex1 = ex2 // Não permitido, erro de compilação\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Para realizar essa atribuição, você teria que usar a sintaxe de conversão e, como elas são idênticas em estrutura, \n\n\n o compilador permitirá isso.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eex1 = example1(ex2) // Permitido, Sem erro de compilação\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n No entanto, se ex2 fosse alterado para ser declarado como um tipo sem nome, \n\n\n usando a mesma declaração exata que ex1, nenhuma sintaxe de conversão seria necessária.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar ex2 struct {\n flag bool\n counter int16\n pi float32\n}\n\nex1 = ex2 // Permitido, Sem precisar utilizar a sintaxe de conversão\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O compilador permitirá essa atribuição sem a necessidade de conversão.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003ePodemos usar a forma literal de struct para inicializar um valor a partir de um tipo de struct.\u003c/li\u003e\n \n \u003cli\u003eO operador ponto (.) nos permite acessar valores de campos individuais.\u003c/li\u003e\n \n \u003cli\u003ePodemos criar structs anonimas.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eCitações\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u0026#34;A conversão implícita de tipos é o especial de Halloween da programação. \n\n\n Quem pensou nisso merece seu próprio inferno especial\u0026#34; - Martin Thompson\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eLeitura adicional\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/07/understanding-type-in-go.html\" target=\"_blank\"\u003eUnderstanding Type in Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/07/object-oriented-programming-in-go.html\" target=\"_blank\"\u003eObject Oriented Programming in Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://dave.cheney.net/2015/10/09/padding-is-hard\" target=\"_blank\"\u003ePadding is hard\u003c/a\u003e - Dave Cheney \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.geeksforgeeks.org/structure-member-alignment-padding-and-data-packing/\" target=\"_blank\"\u003eStructure Member Alignment, Padding and Data Packing\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.catb.org/esr/structure-packing\" target=\"_blank\"\u003eThe Lost Art of Structure Packing\u003c/a\u003e - Eric S. Raymond \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare and initialize struct types.\npackage main\n\nimport \"fmt\"\n\n// example represents a type with different fields.\ntype example struct {\n\tflag bool\n\tcounter int16\n\tpi float32\n}\n\nfunc main() {\n\n\t// Declare a variable of type example set to its\n\t// zero value.\n\tvar e1 example\n\n\t// Display the value.\n\tfmt.Printf(\"%+v\\n\", e1)\n\n\t// Declare a variable of type example and init using\n\t// a struct literal.\n\te2 := example{\n\t\tflag: true,\n\t\tcounter: 10,\n\t\tpi: 3.141592,\n\t}\n\n\t// Display the field values.\n\tfmt.Println(\"Flag\", e2.flag)\n\tfmt.Println(\"Counter\", e2.counter)\n\tfmt.Println(\"Pi\", e2.pi)\n}\n","Hash":"HTIuQGVocDnkwJ/yzY/hNEAYqVA="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare and initialize anonymous\n// struct types.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare a variable of an anonymous type set\n\t// to its zero value.\n\tvar e1 struct {\n\t\tflag bool\n\t\tcounter int16\n\t\tpi float32\n\t}\n\n\t// Display the value.\n\tfmt.Printf(\"%+v\\n\", e1)\n\n\t// Declare a variable of an anonymous type and init\n\t// using a struct literal.\n\te2 := struct {\n\t\tflag bool\n\t\tcounter int16\n\t\tpi float32\n\t}{\n\t\tflag: true,\n\t\tcounter: 10,\n\t\tpi: 3.141592,\n\t}\n\n\t// Display the values.\n\tfmt.Printf(\"%+v\\n\", e2)\n\tfmt.Println(\"Flag\", e2.flag)\n\tfmt.Println(\"Counter\", e2.counter)\n\tfmt.Println(\"Pi\", e2.pi)\n}\n","Hash":"HM74LbBvAkW0dCluD6OHAimtNT0="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how variables of an unnamed type can\n// be assigned to variables of a named type, when they are\n// identical.\npackage main\n\nimport \"fmt\"\n\n// example represents a type with different fields.\ntype example struct {\n\tflag bool\n\tcounter int16\n\tpi float32\n}\n\nfunc main() {\n\n\t// Declare a variable of an anonymous type and init\n\t// using a struct literal.\n\te := struct {\n\t\tflag bool\n\t\tcounter int16\n\t\tpi float32\n\t}{\n\t\tflag: true,\n\t\tcounter: 10,\n\t\tpi: 3.141592,\n\t}\n\n\t// Create a value of type example.\n\tvar ex example\n\n\t// Assign the value of the unnamed struct type\n\t// to the named struct type value.\n\tex = e\n\n\t// Display the values.\n\tfmt.Printf(\"%+v\\n\", ex)\n\tfmt.Printf(\"%+v\\n\", e)\n\tfmt.Println(\"Flag\", e.flag)\n\tfmt.Println(\"Counter\", e.counter)\n\tfmt.Println(\"Pi\", e.pi)\n}\n","Hash":"oganQrg8i79gcdE+fFn3MifWEX4="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// https://github.com/dominikh/go-tools#installation\n// go install honnef.co/go/tools/cmd/...@2023.1.3\n\n// Alignment is about placing fields on address alignment boundaries\n// for more efficient reads and writes to memory.\n\n// Sample program to show how struct types align on boundaries.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"unsafe\"\n)\n\n// No byte padding.\ntype nbp struct {\n\ta bool // \t1 byte\t\t\t\tsizeof 1\n\tb bool // \t1 byte\t\t\t\tsizeof 2\n\tc bool // \t1 byte\t\t\t\tsizeof 3 - Aligned on 1 byte\n}\n\n// Single byte padding.\ntype sbp struct {\n\ta bool //\t1 byte\t\t\t\tsizeof 1\n\t//\t\t\t1 byte padding\t\tsizeof 2\n\tb int16 // \t2 bytes\t\t\t\tsizeof 4 - Aligned on 2 bytes\n}\n\n// Three byte padding.\ntype tbp struct {\n\ta bool //\t1 byte\t\t\t\tsize 1\n\t//\t\t\t3 bytes padding\t\tsize 4\n\tb int32 //\t4 bytes\t\t\t\tsize 8 - Aligned on 4 bytes\n}\n\n// Seven byte padding.\ntype svnbp struct {\n\ta bool //\t1 byte\t\t\t\tsize 1\n\t//\t\t\t7 bytes padding\t\tsize 8\n\tb int64 //\t8 bytes\t\t\t\tsize 16 - Aligned on 8 bytes\n}\n\n// No padding.\ntype np struct {\n\ta string // 16 bytes\t\t\tsize 16\n\tb string // 16 bytes\t\t\tsize 32\n\tc int32 // 4 bytes\t\t\tsize 36\n\td int32 // 4 bytes\t\t\tsize 40 - Aligned on 8 bytes\n}\n\n// Eight byte padding on 64bit Arch. Word size is 8 bytes.\ntype ebp64 struct {\n\ta string //\t16 bytes\t\t\tsize 16\n\tb int32 //\t 4 bytes\t\t\tsize 20\n\t// \t\t 4 bytes padding\tsize 24\n\tc string //\t16 bytes\t\t\tsize 40\n\td int32 //\t 4 bytes\t\t\tsize 44\n\t// \t\t 4 bytes padding\tsize 48 - Aligned on 8 bytes\n}\n\nfunc main() {\n\tvar nbp nbp\n\tsize := unsafe.Sizeof(nbp)\n\tfmt.Printf(\"nbp : SizeOf[%d][%p %p %p]\\n\", size, \u0026nbp.a, \u0026nbp.b, \u0026nbp.c)\n\n\t// -------------------------------------------------------------------------\n\n\tvar sbp sbp\n\tsize = unsafe.Sizeof(sbp)\n\tfmt.Printf(\"sbp : SizeOf[%d][%p %p]\\n\", size, \u0026sbp.a, \u0026sbp.b)\n\n\t// -------------------------------------------------------------------------\n\n\tvar tbp tbp\n\tsize = unsafe.Sizeof(tbp)\n\tfmt.Printf(\"tbp : SizeOf[%d][%p %p]\\n\", size, \u0026tbp.a, \u0026tbp.b)\n\n\t// -------------------------------------------------------------------------\n\n\tvar svnbp svnbp\n\tsize = unsafe.Sizeof(svnbp)\n\tfmt.Printf(\"svnbp: SizeOf[%d][%p %p]\\n\", size, \u0026svnbp.a, \u0026svnbp.b)\n\n\t// -------------------------------------------------------------------------\n\n\tvar np np\n\tsize = unsafe.Sizeof(np)\n\tfmt.Printf(\"np : SizeOf[%d][%p %p %p %p]\\n\", size, \u0026np.a, \u0026np.b, \u0026np.c, \u0026np.d)\n\n\t// -------------------------------------------------------------------------\n\n\tvar ebp64 ebp64\n\tsize = unsafe.Sizeof(ebp64)\n\tfmt.Printf(\"ebp64: SizeOf[%d][%p %p %p %p]\\n\", size, \u0026ebp64.a, \u0026ebp64.b, \u0026ebp64.c, \u0026ebp64.d)\n}\n","Hash":"3Nqm5dE1kJPWKJtyC5ajK0KOToA="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como um ponto de partida para completar os exercícios. Uma solução possível é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Declare um tipo estruturado para manter informações sobre um usuário (nome, email e idade). \n\n\n Crie um valor deste tipo, inicialize com valores e exiba cada campo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Declare e inicialize um tipo estruturado anônimo com os mesmos três campos. Mostre o valor.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct type to maintain information about a user (name, email and age).\n// Create a value of this type, initialize with values and display each field.\n//\n// Declare and initialize an anonymous struct type with the same three fields. Display the value.\npackage main\n\n// Add imports.\n\n// Add user type and provide comment.\n\nfunc main() {\n\n\t// Declare variable of type user and init using a struct literal.\n\n\t// Display the field values.\n\n\t// Declare a variable using an anonymous struct.\n\n\t// Display the field values.\n}\n","Hash":"LQI0gqk8F7QKbKum99HpvZMHr8Y="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct type to maintain information about a user (name, email and age).\n// Create a value of this type, initialize with values and display each field.\n//\n// Declare and initialize an anonymous struct type with the same three fields. Display the value.\npackage main\n\nimport \"fmt\"\n\n// user represents a user in the system.\ntype user struct {\n\tname string\n\temail string\n\tage int\n}\n\nfunc main() {\n\n\t// Declare variable of type user and init using a struct literal.\n\tbill := user{\n\t\tname: \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t\tage: 45,\n\t}\n\n\t// Display the field values.\n\tfmt.Println(\"Name\", bill.name)\n\tfmt.Println(\"Email\", bill.email)\n\tfmt.Println(\"Age\", bill.age)\n\n\t// Declare a variable using an anonymous struct.\n\ted := struct {\n\t\tname string\n\t\temail string\n\t\tage int\n\t}{\n\t\tname: \"Ed\",\n\t\temail: \"ed@ardanlabs.com\",\n\t\tage: 46,\n\t}\n\n\t// Display the field values.\n\tfmt.Println(\"Name\", ed.name)\n\tfmt.Println(\"Email\", ed.email)\n\tfmt.Println(\"Age\", ed.age)\n}\n","Hash":"2fxD14/fOhk6AB1gcC3/73V3JrQ="}]}]} ,"welcome":{"Title":"Bem-vindo","Description":"Bem-vindo ao Ultimate Go tour. Saiba mais sobre o tour antes de começar.","Pages":[{"Title":"Olá, 世界","Content":"\n \u003ch2\u003eOlá, 世界\u003c/h2\u003e\n \n\t\n\t\t\n\t\n\n \n \u003cp\u003e\n Bem-vindo ao tour pela \u003ca href=\"/\" target=\"_self\"\u003elinguagem de programação Go\u003c/a\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O tour está dividido em uma lista de módulos que você pode\n\n\n accessar clicando em\n\n\n \u003ca href=\"javascript:highlight(\u0026#34;.logo\u0026#34;)\" target=\"_self\"\u003eUltimate Go\u003c/a\u003e no canto superior esquerdo da página.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você pode também ver a tabela de conteúdo a qualquer momento clicando no \u003ca href=\"javascript:highlightAndClick(\u0026#34;.nav\u0026#34;)\" target=\"_self\"\u003emenu\u003c/a\u003e no canto superior direito da página.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Ao longo do tour você encontrará uma série de slides e exercícios para você\n\n\n completar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você pode navegar por ele usando\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"javascript:highlight(\u0026#34;.prev-page\u0026#34;)\" target=\"_self\"\u003e\u0026#34;anterior\u0026#34;\u003c/a\u003e ou \u003ccode\u003ePageUp\u003c/code\u003e para ir a página anterior,\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"javascript:highlight(\u0026#34;.next-page\u0026#34;)\" target=\"_self\"\u003e\u0026#34;próximo\u0026#34;\u003c/a\u003e ou \u003ccode\u003ePageDown\u003c/code\u003e para ir a próxima página.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O tour é interativo. Clique no botão\n\n\n \u003ca href=\"javascript:highlightAndClick(\u0026#34;#run\u0026#34;)\" target=\"_self\"\u003eRun\u003c/a\u003e agora\n\n\n (ou tecle \u003ccode\u003eShift\u003c/code\u003e + \u003ccode\u003eEnter\u003c/code\u003e) para compilar e executar o programa no\n\n\n seu computador.\n\n\n O resultado é mostrado abaixo do código.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Estes exemplos de programas demonstram os diferentes aspectos de Go. Os programas do tour são destinados a serem pontos de partida para sua própria experimentação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Edite o programa e execute novamente.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Observe que quando você clica em \u003ca href=\"javascript:highlightAndClick(\u0026#34;#format\u0026#34;)\" target=\"_self\"\u003eFormatar\u003c/a\u003e\n\n\n (shortcut: \u003ccode\u003eCtrl\u003c/code\u003e + \u003ccode\u003eEnter\u003c/code\u003e), o texto no editor é formatado usando a ferramenta\n\n\n \u003ca href=\"/cmd/gofmt/\" target=\"_self\"\u003egofmt\u003c/a\u003e. Você pode ligar ou desligar o destaque de sintaxe\n\n\n clicando no botão \u003ca href=\"javascript:highlightAndClick(\u0026#34;.syntax-checkbox\u0026#34;)\" target=\"_self\"\u003esintaxe\u003c/a\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando você estiver pronto para seguir em frente, clique na \u003ca href=\"javascript:highlightAndClick(\u0026#34;.next-page\u0026#34;)\" target=\"_self\"\u003eseta para direita\u003c/a\u003e abaixo ou aperte a tecla \u003ccode\u003ePageDown\u003c/code\u003e.\n \u003c/p\u003e\n \n\n","Files":[{"Name":"hello.go","Content":"package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, 世界\")\n}\n","Hash":"DwfZCJ2NK3FTIJnSUkZkwzma41c="}]},{"Title":"Go offline (opcional)","Content":"\n \u003ch2\u003eGo offline (opcional)\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este tour também está disponível como um programa autônomo que você pode usar sem acesso à internet. Ele compila e executa os exemplos de código na sua própria máquina.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Para executar o tour localmente, você vai precisar primeiro \u003ca href=\"https://go.dev/doc/install\" target=\"_blank\"\u003einstalar o Go\u003c/a\u003e e então executar:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ego install github.com/ardanlabs/gotour/cmd/tour@latest\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Isso vai colocar um binário do tour no diretório bin do seu \u003ca href=\"https://go.dev/cmd/go/#hdr-GOPATH_and_Modules\" target=\"_blank\"\u003eGOPATH\u003c/a\u003e. Ao executar o programa do tour, um navegador web será aberto exibindo sua versão local do tour.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Ou, claro, você pode continuar o tour através deste web site.\n \u003c/p\u003e\n \n\n","Files":[]},{"Title":"O Playground Go","Content":"\n \u003ch2\u003eO Playground Go\u003c/h2\u003e\n \n\t\n\t\t\n\t\n\n \n \u003cp\u003e\n Este tour foi construído sobre o \u003ca href=\"https://play.golang.org/\" target=\"_blank\"\u003eGo Playground\u003c/a\u003e, um serviço web que é executado nos servidores de \u003ca href=\"https://go.dev/\" target=\"_blank\"\u003egolang.org\u003c/a\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O serviço recebe um programa Go, compila, linka, e executa o programa dentro de uma \u0026#34;sandbox\u0026#34; e então retorna o resultado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Existem limitações para os programas que podem ser executados no playground:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n No playground, o tempo começa em 2009-11-10 23:00:00 UTC (determinar o significado desta data é um exercício para o leitor). Isso torna mais fácil armazenar programas em cache, dando-lhes uma saída determinística.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Há também limites para o tempo de execução, de CPU e uso de memória, e o programa não pode acessar hosts de rede externos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O playground usa a última versão estável do Go.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Leia \u0026#34;\u003ca href=\"https://go.dev/blog/playground\" target=\"_blank\"\u003eInside the Go Playground\u003c/a\u003e\u0026#34; para saber mais.\n \u003c/p\u003e\n \n\n","Files":[{"Name":"sandbox.go","Content":"package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\tfmt.Println(\"Welcome to the playground!\")\n\n\tfmt.Println(\"The time is\", time.Now())\n}\n","Hash":"bOpKtZ8cTKG+qhINnOZDcJhhNQc="}]},{"Title":"Contribua Com O Projeto","Content":"\n \u003ch2\u003eContribua Com O Projeto\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eComo\u003c/b\u003e \u003cb\u003eComeçar\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se você estiver interessado em adicionar mais seções ou conteúdos ao projeto, por favor\n\n\n crie um issue no repositório. Basta fornecer uma ideia geral do conteúdo que você quer\n\n\n adicionar e o por quê. Se você já tem um código de exemplo, por favor compartilhe.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003ca href=\"https://github.com/ardanlabs/gotour\" target=\"_blank\"\u003ehttps://github.com/ardanlabs/gotour\u003c/a\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nós vamos discutir o issue e se aprovado, você pode enviar um PR. Nós adoraríamos\n\n\n mais exemplos e tópicos sobre algoritmos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eNovos\u003c/b\u003e \u003cb\u003eIdiomas\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Também adoraríamos ter o conteúdo traduzido em diferentes idiomas.\n\n\n Se você estiver interessado, por favor crie um issue. Podemos compensar por\n\n\n esse esforço.\n \u003c/p\u003e\n \n\n","Files":[]},{"Title":"Sobre Ardan Labs","Content":"\n \u003ch2\u003eSobre Ardan Labs\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eConsultoria\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003eSoftware\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003eAlto\u003c/b\u003e \u003cb\u003eDesempenho\u003c/b\u003e, \u003cb\u003eTreinamento\u003c/b\u003e, \u003cb\u003eRecrutamento,\u003c/b\u003e \u003cb\u003e\u0026amp;\u003c/b\u003e \u003cb\u003eDesenvolvimento\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esteja você procurando por ajuda com Go, Rust, Kubernetes, Terraform ou\n\n\n Blockchain, Ardan Labs é o seu parceiro estratégico para soluções de software de alto desempenho.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Informe-se sobre eventos de treinamento corporativo, sessões de treinamento ao vivo com inscrições abertas,\n\n\n e opções de aprendizagem sob demanda.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Ardan Labs (\u003ca href=\"https://www.ardanlabs.com\" target=\"_blank\"\u003ewww.ardanlabs.com\u003c/a\u003e)\n\n\n - \u003ca href=\"mailto:hello@ardanlabs.com\" target=\"_blank\"\u003ehello@ardanlabs.com\u003c/a\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Para participar de qualquer um dos nossos treinamentos de alto desempenho confira esse link:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training\" target=\"_blank\"\u003ewww.ardanlabs.com/training\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \u003ch2\u003eMais Materiais\u003c/h2\u003e\n \n \n \u003cp\u003e\n Todo o material da aula Ultimate Go pode ser encontrado nesse repositório\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/courses/go/README.md\" target=\"_blank\"\u003eRepositório Ultimate Go\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Dê uma olhada no documento de design antes de começar para entrar na mentalidade certa\n\n\n para aprender a linguagem.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/go/README.md\" target=\"_blank\"\u003eDocumento de Design\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O repositório tem mais tópicos que não serão cobertos pelo Go tour, então confira-os quando você terminar.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/courses/go/tooling/README.md\" target=\"_blank\"\u003eTeste, Benchmarking, e Profiling\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/courses/go/packages/README.md\" target=\"_blank\"\u003ePacotes da Biblioteca Padrão\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eUltimate Go Notebook\u003c/h2\u003e\n \n \n \u003cp\u003e\n Todo esse material e mais também pode ser encontrado em Ultimate Go Notebook\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/ultimate-go-notebook/\" target=\"_blank\"\u003eUltimate Go Notebook\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003ePreciso de Ajuda\u003c/h2\u003e\n \n \n \u003cp\u003e\n Não hesite em entrar em contato com Bill Kennedy at Ardan labs se tiver problemas\n\n\n ou dúvidas\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003ca href=\"mailto:bill@ardanlabs.com\" target=\"_blank\"\u003ebill@ardanlabs.com\u003c/a\u003e\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNossa Experiência\u003c/h2\u003e\n \n \n \u003cp\u003e\n Nós ensinamos Go para milhares de desenvolvedores ao redor do mundo desde 2014. Não\n\n\n existe nenhuma outra empresa que faz isso há mais tempo e nosso material se provou\n\n\n ajudar a impulsionar desenvolvedores de 6 a 12 meses à frente em conhecimentos em Go. Nós sabemos\n\n\n quais conhecimentos os desenvolvedores precisam para serem produtivos e eficientes ao escrever\n\n\n software em Go.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nossas aulas são perfeitas para desenvolvedores de nível intermediário que possuem pelo menos alguns\n\n\n meses a anos de experiência escrevendo código em Go. Nossas aulas proporcionam um\n\n\n conhecimento muito profundo sobre a linguagem de programação com um grande foco em mecânicas da linguagem,\n\n\n filosofias de design e guidelines. Nós focamos em ensinar como escrever código priorizando\n\n\n consistência, integridade, legibilidade e simplicidade. Nós falamos muito sobre \u0026#34;se\n\n\n desempenho é importante\u0026#34; com foco em simpatia mecânica, design orientado a dados,\n\n\n desacoplamento e escrever/debugar software de produção.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNosso Professor\u003c/h2\u003e\n \n \n \u003cp\u003e\n William Kennedy é sócio-gerente da Ardan Labs em Miami, Flórida. Ardan Labs\n\n\n é uma empresa de desenvolvimento e treinamento de alto desempenho que trabalha com\n\n\n startups e empresas da Fortune 500. Ele é também coautor do livro Go in Action,\n\n\n autor do blog GoingGo.Net, e membro fundador do GoBridge que está trabalhando\n\n\n para aumentar a adoção do Go por meio da diversidade.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eTreinamento\u003c/b\u003e \u003cb\u003eem\u003c/b\u003e \u003cb\u003eVídeo\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://education.ardanlabs.com/\" target=\"_blank\"\u003eVídeo Ultimate Go\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://youtube.ardanlabs.com/\" target=\"_blank\"\u003eCanal no Youtube da Ardan Labs\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eBlog\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/\" target=\"_blank\"\u003eArdan Labs Blog Técnico\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003ePodcasts\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://ardanlabs.buzzsprout.com/\" target=\"_blank\"\u003eArdan Labs Podcast: Séries em Andamento\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eMais Sobre Go\u003c/h2\u003e\n \n \n \u003cp\u003e\n Go é uma linguagem de programação de código aberto que facilita construir\n\n\n um software simples, confiável, e eficiente. Embora ela tome emprestadas ideias de linguagens existentes,\n\n\n ela possui uma natureza simples e única que torna os programas Go diferentes em caráter dos\n\n\n programas escritos em outras linguagens. Ela equilibra os recursos de uma linguagem de sistemas\n\n\n de baixo nível com alguns recursos de alto nível que você vê em linguagens modernas hoje.\n\n\n Isso cria um ambiente de programação que permite que você seja incrivelmente produtivo,\n\n\n eficiente e tenha total controle; em Go, você pode escrever menos código e fazer muito mais.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Go é a fusão de desempenho e produtividade em uma linguagem que os desenvolvedores de software\n\n\n podem aprender, usar e entender. Go não é C, ainda sim nós temos muitos dos \n\n\n benefícios de C com os benefícios de uma linguagem de programação de alto nível.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://henvic.dev/posts/go/\" target=\"_blank\"\u003eThe Ecosystem of the Go Programming Language - Henrique Vicente\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.infoq.com/presentations/go-concurrency-gc\" target=\"_blank\"\u003eThe Why of Go - Carmen Andoh\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/ardanlabs/gotraining#:~:text=Go%20Ten%20Years%20and%20Climbing\" target=\"_blank\"\u003eGo Ten Years and Climbing - Rob Pike\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/ardanlabs/gotraining#:~:text=The%20eigenvector%20of%20%22Why%20we%20moved%20from%20language%20X%20to%20language%20Y%22\" target=\"_blank\"\u003eThe eigenvector of \u0026#34;Why we moved from language X to language Y\u0026#34; - Erik Bernhardsson\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://talks.golang.org/2012/splash.article\" target=\"_blank\"\u003eLearn More - Go Team\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/ardanlabs/gotraining#:~:text=Simplicity%20is%20Complicated\" target=\"_blank\"\u003eSimplicity is Complicated - Rob Pike\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://aarti.github.io/2016/08/13/getting-started-in-go\" target=\"_blank\"\u003eGetting Started In Go - Aarti Parikh\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Importante\u003c/h2\u003e\n \n \n \u003cp\u003e\n Por favor, verifique esta página de \u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/reading/README.md\" target=\"_blank\"\u003eleitura importante\u003c/a\u003e.\n\n\n Você encontrará artigos e vídeos sobre simpatia mecânica, design orientado a dados,\n\n\n Go runtime e otimizações e artigos sobre a história da computação.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eJunte-se à Comunidade Go no Slack\u003c/h2\u003e\n \n \n \u003cp\u003e\n Nós usamos um canal no Slack para compartilhar links, códigos e exemplos durante o treinamento.\n\n\n Ele é grátis. Essa é também a mesma comunidade do Slack que você usará depois do treinamento\n\n\n para pedir ajuda e interagir com muitos experts em Go ao redor do mundo na comunidade.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eUsando o link a seguir, preencha seu nome e endereço de email: \u003ca href=\"https://invite.slack.gobridge.org/\" target=\"_blank\"\u003ehttps://invite.slack.gobridge.org\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003eVerifique seu email e siga o link para o aplicativo Slack.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[]}]} ,"channels":{"Title":"Channels","Description":"Channels permitem que goroutines se comuniquem entre si por meio do uso de semântica de sinais.","Pages":[{"Title":"Channels","Content":"\n \u003ch2\u003eChannels\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n É importante pensar em um \u003cb\u003echannel\u003c/b\u003e não como uma estrutura de dados, mas como um mecanismo\n\n\n de sinalização. Isso está alinhado com a ideia de que você envia e recebe em um \u003cb\u003echannel\u003c/b\u003e, não lê e escreve.\n\n\n Se o problema à sua frente não pode ser resolvido com sinalização, se a palavra sinalização não está\n\n\n sendo mencionada, você precisa questionar o uso de \u003cb\u003echannels\u003c/b\u003e.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Aguardar pelo resultado\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Distribuir tarefas (Fan out)\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Aguardar pela tarefa\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Pooling (Agrupamento)\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Semáforo de distribuição (Fan out semaphore)\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e Agrupamento de trabalho limitado\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e7:\u003c/b\u003e Descartar (Drop)\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e8:\u003c/b\u003e Cancelamento\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e9:\u003c/b\u003e Retentativas com limite de tempo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e10:\u003c/b\u003e Cancelamento de canal\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eMecânica de Channels\u003c/h2\u003e\n \n \n \u003cp\u003e\n O custo de ter a garantia no nível de sinalização é a latência desconhecida.\n\n\n O remetente não saberá por quanto tempo ele precisa esperar que o destinatário\n\n\n aceite o sinal. Ter que esperar pelo destinatário cria uma latência bloqueante.\n\n\n Nesse caso, quantidades desconhecidas de latência de bloqueio. O remetente precisa esperar,\n\n\n por um período de tempo desconhecido, até que o destinatário esteja disponível para receber o sinal.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esperar pelo destinatário significa mecanicamente que a operação de recebimento ocorre antes\n\n\n do envio. Com canais, o recebimento ocorre nanossegundos antes, mas ainda é antes.\n\n\n Isso significa que o destinatário pega o sinal e depois se afasta, permitindo que o\n\n\n remetente prossiga com uma garantia.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n E se o processo não puder esperar por um período de tempo desconhecido?\n\n\n E se esse tipo de latência não funcionar? Nesse caso, a garantia não pode estar no\n\n\n nível de sinalização; ela precisa estar fora dele. A mecânica por trás disso é que o\n\n\n envio agora ocorre antes do recebimento. O remetente pode realizar o sinal sem precisar\n\n\n que o destinatário esteja disponível. Portanto, o remetente pode se afastar e não precisa esperar.\n\n\n Eventualmente, espera-se que o destinatário apareça e pegue o sinal.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Isso reduz o custo de latência no envio, mas cria incerteza sobre os sinais sendo recebidos e,\n\n\n portanto, sobre a detecção de problemas \u003cb\u003eupstream\u003c/b\u003e com os destinatários. Isso pode fazer\n\n\n com que o processo aceite trabalho que nunca é iniciado ou concluído.\n\n\n Isso poderia eventualmente causar uma pressão massiva e fazer com que os sistemas travem.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A segunda coisa a se concentrar é se você precisa enviar dados com o sinal.\n\n\n Se o sinal exigir a transmissão de dados, então a sinalização é uma relação 1 para 1\n\n\n entre Goroutines. Se uma nova Goroutine também precisa receber o sinal, um segundo sinal\n\n\n deve ser enviado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se os dados não precisarem ser transmitidos com o sinal, então o sinal pode ser uma\n\n\n relação 1 para 1 ou 1 para muitos entre Goroutines. Sinalização sem dados é usada\n\n\n principalmente para cancelamento ou desligamento. Isso é feito fechando o channel.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A terceira coisa a se concentrar é o estado do \u003cb\u003echannel\u003c/b\u003e. Um \u003cb\u003echannel\u003c/b\u003e pode estar em 1 de 3 estados.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Um \u003cb\u003echannel\u003c/b\u003e pode estar em um estado nulo, construindo o \u003cb\u003echannel\u003c/b\u003e para o seu estado de zero value.\n\n\n Envios e recebimentos em canais neste estado serão bloqueados.\n\n\n Isso é útil em situações onde você deseja implementar paradas de curto prazo no trabalho.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Um \u003cb\u003echannel\u003c/b\u003e pode estar em um estado aberto usando a função integrada \u0026#34;make\u0026#34;.\n\n\n Envios e recebimentos em canais neste estado funcionarão sob as seguintes condições:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eUnbuffered\u003c/b\u003e \u003cb\u003eChannels:\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eGarantias no nível de sinalização com o recebimento ocorrendo antes do envio.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n As Goroutines de envio e recebimento precisam se encontrar no mesmo espaço e\n\n\n tempo para que um sinal seja processado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eBuffered\u003c/b\u003e \u003cb\u003eChannels:\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eGarantias fora do nível de sinalização, com o envio ocorrendo antes do recebimento.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Se o buffer não estiver cheio, os envios podem ser concluídos, caso contrário, eles\n\n\n bloqueiam. Se o buffer não estiver vazio, as recepções podem ser concluídas,\n\n\n caso contrário, elas bloqueiam.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Um \u003cb\u003echannel\u003c/b\u003e pode estar em um estado fechado usando a função integrada \u003cb\u003eclose\u003c/b\u003e.\n\n\n Você não precisa fechar um \u003cb\u003echannel\u003c/b\u003e para liberar memória, isso é para alterar o estado.\n\n\n Enviar em um \u003cb\u003echannel\u003c/b\u003e fechado causará um pânico, no entanto, receber em um \u003cb\u003echannel\u003c/b\u003e fechado\n\n\n retornará imediatamente.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Com todas essas informações, você pode se concentrar em padrões de canal.\n\n\n A ênfase na sinalização é importante. A ideia é determinar se você precisa ou não de\n\n\n uma garantia no nível de sinalização, com base nas preocupações com a latência. Se você\n\n\n precisa ou não transmitir dados com o sinal, com base no tratamento de cancelamentos ou não.\n\n\n Você deseja converter a sintaxe para essas semânticas.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eOrientação de design\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eAprenda sobre o \u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/go/#channel-design\" target=\"_blank\"\u003eOrientação de design\u003c/a\u003e para channels.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eDiagramas\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eGarantia\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003eEntrega\u003c/b\u003e - (Guarantee Of Delivery)\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A `Garantia de Entrega`, É baseada em uma única pergunta: \u0026#34;Eu preciso da\n\n\n garantia de que o sinal enviado por uma determinada goroutine foi recebido?\u0026#34;\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/guarantee_of_delivery.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/guarantee_of_delivery.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eSinalização\u003c/b\u003e \u003cb\u003eCom\u003c/b\u003e \u003cb\u003eou\u003c/b\u003e \u003cb\u003eSem\u003c/b\u003e \u003cb\u003eDados\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando você vai sinalizar \u003ccode\u003ecom\u003c/code\u003e dados, existem três opções de configuração de\n\n\n \u003cb\u003echannel\u003c/b\u003e que você pode escolher, dependendo do tipo de \u003ccode\u003egarantia\u003c/code\u003e que você precisa.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/signaling_with_data.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/signaling_with_data.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Ela permite que uma goroutine sinalize outra goroutine para cancelar o que estão fazendo\n\n\n e seguir em frente. O cancelamento pode ser implementado usando canais tanto\n\n\n `não bufferizados` quanto \u003ccode\u003ebufferizados\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/signaling_without_data.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/signaling_without_data.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eEstado\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O comportamento de um canal é diretamente influenciado pelo seu \u003ccode\u003eestado\u003c/code\u003e atual.\n\n\n O \u003ccode\u003eestado\u003c/code\u003e de um canal pode ser \u003ccode\u003enulo\u003c/code\u003e, \u003ccode\u003eaberto\u003c/code\u003e ou \u003ccode\u003efechado\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/state.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/state.png\"\u003e\n \u003c/a\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2017/10/the-behavior-of-channels.html\" target=\"_blank\"\u003eThe Behavior Of Channels\u003c/a\u003e - William Kennedy\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/ref/mem#tmp_7\" target=\"_blank\"\u003eChannel Communication\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/share-memory-by-communicating\" target=\"_blank\"\u003eShare Memory By Communicating\u003c/a\u003e - Andrew Gerrand\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/02/the-nature-of-channels-in-go.html\" target=\"_blank\"\u003eThe Nature Of Channels In Go\u003c/a\u003e - William Kennedy\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://matt-welsh.blogspot.com/2010/07/retrospective-on-seda.html\" target=\"_blank\"\u003eA Retrospective on SEDA\u003c/a\u003e - Matt Welsh\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=KBZlN0izeiY\" target=\"_blank\"\u003eUnderstanding Channels\u003c/a\u003e - Kavya Joshi\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eBuffer Bloat - 2011\u003c/h2\u003e\n \n \n \u003cp\u003e\n Tenha cuidado ao usar buffers grandes com a ideia de reduzir a latência.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eBuffers grandes impedem a notificação oportuna da pressão de retorno.\u003c/li\u003e\n \n \u003cli\u003eEles prejudicam sua capacidade de reduzir a pressão de retorno de forma oportuna.\u003c/li\u003e\n \n \u003cli\u003eEles podem aumentar a latência, não reduzi-la.\u003c/li\u003e\n \n \u003cli\u003eUse buffered channels para fornecer uma maneira de manter a continuidade.\u003c/li\u003e\n \n \u003cli\u003eNão os use apenas para desempenho.\u003c/li\u003e\n \n \u003cli\u003eUse-os para lidar com explosões de dados bem definidas.\u003c/li\u003e\n \n \u003cli\u003eUse-os para lidar com problemas de velocidade da luz entre as transferências.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eVídeos\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=qbIozKVz73g\" target=\"_blank\"\u003eBufferbloat: Dark Buffers in the Internet\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.bufferbloat.net/projects/cerowrt/wiki/Bloat-videos\" target=\"_blank\"\u003eBuffer Bloat Videos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the wait for result channel pattern.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\nfunc main() {\n\twaitForResult()\n}\n\n// waitForResult: In this pattern, the parent goroutine waits for the child\n// goroutine to finish some work to signal the result.\nfunc waitForResult() {\n\tch := make(chan string)\n\n\tgo func() {\n\t\ttime.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)\n\t\tch \u003c- \"data\"\n\t\tfmt.Println(\"child : sent signal\")\n\t}()\n\n\td := \u003c-ch\n\tfmt.Println(\"parent : recv'd signal :\", d)\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"VlmpG8G/hHkOV2tzgehEFXkii0A="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the fan out channel pattern.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\nfunc main() {\n\tfanOut()\n}\n\n// fanOut: In this pattern, the parent goroutine creates 2000 child goroutines\n// and waits for them to signal their results.\nfunc fanOut() {\n\tchildren := 2000\n\tch := make(chan string, children)\n\n\tfor c := 0; c \u003c children; c++ {\n\t\tgo func(child int) {\n\t\t\ttime.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)\n\t\t\tch \u003c- \"data\"\n\t\t\tfmt.Println(\"child : sent signal :\", child)\n\t\t}(c)\n\t}\n\n\tfor children \u003e 0 {\n\t\td := \u003c-ch\n\t\tchildren--\n\t\tfmt.Println(d)\n\t\tfmt.Println(\"parent : recv'd signal :\", children)\n\t}\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"i9Whe27FA3vNr66vDb9O2feIbt8="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the wait for task channel pattern.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\nfunc main() {\n\twaitForTask()\n}\n\n// waitForTask: In this pattern, the parent goroutine sends a signal to a\n// child goroutine waiting to be told what to do.\nfunc waitForTask() {\n\tch := make(chan string)\n\n\tgo func() {\n\t\td := \u003c-ch\n\t\tfmt.Println(\"child : recv'd signal :\", d)\n\t}()\n\n\ttime.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)\n\tch \u003c- \"data\"\n\tfmt.Println(\"parent : sent signal\")\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"ChPf/rRJZX5gh/AY8N/s8m7wnLc="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the pooling channel pattern.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"time\"\n)\n\nfunc main() {\n\tpooling()\n}\n\n// pooling: In this pattern, the parent goroutine signals 100 pieces of work\n// to a pool of child goroutines waiting for work to perform.\nfunc pooling() {\n\tch := make(chan string)\n\n\tg := runtime.GOMAXPROCS(0)\n\tfor c := 0; c \u003c g; c++ {\n\t\tgo func(child int) {\n\t\t\tfor d := range ch {\n\t\t\t\tfmt.Printf(\"child %d : recv'd signal : %s\\n\", child, d)\n\t\t\t}\n\t\t\tfmt.Printf(\"child %d : recv'd shutdown signal\\n\", child)\n\t\t}(c)\n\t}\n\n\tconst work = 100\n\tfor w := 0; w \u003c work; w++ {\n\t\tch \u003c- \"data\"\n\t\tfmt.Println(\"parent : sent signal :\", w)\n\t}\n\n\tclose(ch)\n\tfmt.Println(\"parent : sent shutdown signal\")\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"rq6cw/JialxY4RSB8XT5V1Rnr3c="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the fan out semaphore channel pattern.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"runtime\"\n\t\"time\"\n)\n\nfunc main() {\n\tfanOutSem()\n}\n\n// fanOutSem: In this pattern, a semaphore is added to the fan out pattern\n// to restrict the number of child goroutines that can be schedule to run.\nfunc fanOutSem() {\n\tchildren := 2000\n\tch := make(chan string, children)\n\n\tg := runtime.GOMAXPROCS(0)\n\tsem := make(chan bool, g)\n\n\tfor c := 0; c \u003c children; c++ {\n\t\tgo func(child int) {\n\t\t\tsem \u003c- true\n\t\t\t{\n\t\t\t\tt := time.Duration(rand.Intn(200)) * time.Millisecond\n\t\t\t\ttime.Sleep(t)\n\t\t\t\tch \u003c- \"data\"\n\t\t\t\tfmt.Println(\"child : sent signal :\", child)\n\t\t\t}\n\t\t\t\u003c-sem\n\t\t}(c)\n\t}\n\n\tfor children \u003e 0 {\n\t\td := \u003c-ch\n\t\tchildren--\n\t\tfmt.Println(d)\n\t\tfmt.Println(\"parent : recv'd signal :\", children)\n\t}\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"IpDd6Fq56OGiBYtCXkeY0TySNYQ="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the bounded work pooling channel pattern.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n)\n\nfunc main() {\n\tboundedWorkPooling()\n}\n\n// boundedWorkPooling: In this pattern, a pool of child goroutines is created\n// to service a fixed amount of work. The parent goroutine iterates over all\n// work, signalling that into the pool. Once all the work has been signaled,\n// then the channel is closed, the channel is flushed, and the child\n// goroutines terminate.\nfunc boundedWorkPooling() {\n\twork := []string{\"paper\", \"paper\", \"paper\", \"paper\", 2000: \"paper\"}\n\n\tg := runtime.GOMAXPROCS(0)\n\tvar wg sync.WaitGroup\n\twg.Add(g)\n\n\tch := make(chan string, g)\n\n\tfor c := 0; c \u003c g; c++ {\n\t\tgo func(child int) {\n\t\t\tdefer wg.Done()\n\t\t\tfor wrk := range ch {\n\t\t\t\tfmt.Printf(\"child %d : recv'd signal : %s\\n\", child, wrk)\n\t\t\t}\n\t\t\tfmt.Printf(\"child %d : recv'd shutdown signal\\n\", child)\n\t\t}(c)\n\t}\n\n\tfor _, wrk := range work {\n\t\tch \u003c- wrk\n\t}\n\tclose(ch)\n\twg.Wait()\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"hgBLIhRwJw3E1tYLi30Kxf88YK0="},{"Name":"example7.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the drop channel pattern.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\tdrop()\n}\n\n// drop: In this pattern, the parent goroutine signals 2000 pieces of work to\n// a single child goroutine that can't handle all the work. If the parent\n// performs a send and the child is not ready, that work is discarded and dropped.\nfunc drop() {\n\tconst cap = 100\n\tch := make(chan string, cap)\n\n\tgo func() {\n\t\tfor p := range ch {\n\t\t\tfmt.Println(\"child : recv'd signal :\", p)\n\t\t}\n\t}()\n\n\tconst work = 2000\n\tfor w := 0; w \u003c work; w++ {\n\t\tselect {\n\t\tcase ch \u003c- \"data\":\n\t\t\tfmt.Println(\"parent : sent signal :\", w)\n\t\tdefault:\n\t\t\tfmt.Println(\"parent : dropped data :\", w)\n\t\t}\n\t}\n\n\tclose(ch)\n\tfmt.Println(\"parent : sent shutdown signal\")\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"BXPXIBRkQQ4xg01Cx7KkcRNwwjM="},{"Name":"example8.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the cancellation channel pattern.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\nfunc main() {\n\tcancellation()\n}\n\n// cancellation: In this pattern, the parent goroutine creates a child\n// goroutine to perform some work. The parent goroutine is only willing to\n// wait 150 milliseconds for that work to be completed. After 150 milliseconds\n// the parent goroutine walks away.\nfunc cancellation() {\n\tduration := 150 * time.Millisecond\n\tctx, cancel := context.WithTimeout(context.Background(), duration)\n\tdefer cancel()\n\n\tch := make(chan string, 1)\n\n\tgo func() {\n\t\ttime.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)\n\t\tch \u003c- \"data\"\n\t}()\n\n\tselect {\n\tcase d := \u003c-ch:\n\t\tfmt.Println(\"work complete\", d)\n\n\tcase \u003c-ctx.Done():\n\t\tfmt.Println(\"work cancelled\")\n\t}\n\n\ttime.Sleep(time.Second)\n\tfmt.Println(\"-------------------------------------------------\")\n}\n","Hash":"FO1T2zSNxBlkefSUkeEB1EIv4bg="},{"Name":"example9.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the retry timeout channel pattern.\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\tretryTimeout(ctx, time.Second, func(ctx context.Context) error { return errors.New(\"always fail\") })\n}\n\n// retryTimeout: You need to validate if something can be done with no error\n// but it may take time before this is true. You set a retry interval to create\n// a delay before you retry the call and you use the context to set a timeout.\nfunc retryTimeout(ctx context.Context, retryInterval time.Duration, check func(ctx context.Context) error) {\n\n\tfor {\n\t\tfmt.Println(\"perform user check call\")\n\t\tif err := check(ctx); err == nil {\n\t\t\tfmt.Println(\"work finished successfully\")\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Println(\"check if timeout has expired\")\n\t\tif ctx.Err() != nil {\n\t\t\tfmt.Println(\"time expired 1 :\", ctx.Err())\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Printf(\"wait %s before trying again\\n\", retryInterval)\n\t\tt := time.NewTimer(retryInterval)\n\n\t\tselect {\n\t\tcase \u003c-ctx.Done():\n\t\t\tfmt.Println(\"timed expired 2 :\", ctx.Err())\n\t\t\tt.Stop()\n\t\t\treturn\n\t\tcase \u003c-t.C:\n\t\t\tfmt.Println(\"retry again\")\n\t\t}\n\t}\n}\n","Hash":"90t6SK9TVDJp/+U95oN0aYoa3Kw="},{"Name":"example10.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program demonstrates the channel cancellation channel pattern.\npackage main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tstop := make(chan struct{})\n\n\tchannelCancellation(stop)\n}\n\n// channelCancellation shows how you can take an existing channel being\n// used for cancellation and convert that into using a context where\n// a context is needed.\nfunc channelCancellation(stop \u003c-chan struct{}) {\n\n\t// Create a cancel context for handling the stop signal.\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\t// If a signal is received on the stop channel, cancel the\n\t// context. This will propagate the cancel into the p.Run\n\t// function below.\n\tgo func() {\n\t\tselect {\n\t\tcase \u003c-stop:\n\t\t\tcancel()\n\t\tcase \u003c-ctx.Done():\n\t\t}\n\t}()\n\n\t// Imagine a function that is performing an I/O operation that is\n\t// cancellable.\n\tfunc(ctx context.Context) error {\n\t\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, \"https://www.ardanlabs.com/blog/index.xml\", nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = http.DefaultClient.Do(req)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}(ctx)\n}\n","Hash":"Qg0BSL8H0kH81jZrPkyhThwj+5I="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Utilize o template como ponto de partida para concluir os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Escreva um programa no qual duas goroutines passem um inteiro de um lado para o outro dez vezes.\n\n\n Exiba quando cada goroutine receber o inteiro. Incremente o inteiro a cada passagem.\n\n\n Uma vez que o inteiro atingir o valor de dez, encerre o programa de forma limpa.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExercício 2\u003c/h2\u003e\n \n \n \u003cp\u003e\n Escreva um programa que utilize um padrão de expansão (fan out) para gerar 100 números\n\n\n aleatórios de forma concorrente. Cada goroutine deve gerar um único número aleatório e\n\n\n retornar esse número para a goroutine principal por meio de um *buffered channel*. Defina o\n\n\n tamanho do *buffered channel* de modo que nenhum envio bloqueie. Não aloque mais buffers do\n\n\n que você precisa. A goroutine principal deve exibir cada número aleatório que ela recebe e,\n\n\n em seguida, encerrar o programa.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExercício 3\u003c/h2\u003e\n \n \n \u003cp\u003e\n Escreva um programa que gere até 100 números aleatórios de forma concorrente.\n\n\n Não envie todos os 100 valores, de modo que o número de envios/recebimentos seja desconhecido.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExercício 4\u003c/h2\u003e\n \n \n \u003cp\u003e\n Escreva um programa que gere até 100 números aleatórios de forma concorrente usando um\n\n\n *worker pool*. Rejeite valores pares. Instrua os \u003cb\u003eworkers\u003c/b\u003e a encerrarem\n\n\n quando 100 números ímpares forem coletados.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program where two goroutines pass an integer back and forth\n// ten times. Display when each goroutine receives the integer. Increment\n// the integer with each pass. Once the integer equals ten, terminate\n// the program cleanly.\npackage main\n\n// Add imports.\n\nfunc main() {\n\n\t// Create an unbuffered channel.\n\n\t// Create the WaitGroup and add a count\n\t// of two, one for each goroutine.\n\n\t// Launch the goroutine and handle Done.\n\n\t// Launch the goroutine and handle Done.\n\n\t// Send a value to start the counting.\n\n\t// Wait for the program to finish.\n}\n\n// goroutine simulates sharing a value.\nfunc goroutine( /* parameters */ ) {\n\tfor {\n\n\t\t// Wait for the value to be sent.\n\t\t// If the channel was closed, return.\n\n\t\t// Display the value.\n\n\t\t// Terminate when the value is 10.\n\n\t\t// Increment the value and send it\n\t\t// over the channel.\n\t}\n}\n","Hash":"wHIisaEHI+s1a5140HbK9taZnF4="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program where two goroutines pass an integer back and forth\n// ten times. Display when each goroutine receives the integer. Increment\n// the integer with each pass. Once the integer equals ten, terminate\n// the program cleanly.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\t// Create an unbuffered channel.\n\tshare := make(chan int)\n\n\t// Create the WaitGroup and add a count\n\t// of two, one for each goroutine.\n\tvar wg sync.WaitGroup\n\twg.Add(2)\n\n\t// Launch two goroutines.\n\tgo func() {\n\t\tgoroutine(\"Bill\", share)\n\t\twg.Done()\n\t}()\n\n\tgo func() {\n\t\tgoroutine(\"Joan\", share)\n\t\twg.Done()\n\t}()\n\n\t// Start the sharing.\n\tshare \u003c- 1\n\n\t// Wait for the program to finish.\n\twg.Wait()\n}\n\n// goroutine simulates sharing a value.\nfunc goroutine(name string, share chan int) {\n\tfor {\n\n\t\t// Wait to receive a value.\n\t\tvalue, ok := \u003c-share\n\t\tif !ok {\n\n\t\t\t// If the channel was closed, return.\n\t\t\tfmt.Printf(\"Goroutine %s Down\\n\", name)\n\t\t\treturn\n\t\t}\n\n\t\t// Display the value.\n\t\tfmt.Printf(\"Goroutine %s Inc %d\\n\", name, value)\n\n\t\t// Terminate when the value is 10.\n\t\tif value == 10 {\n\t\t\tclose(share)\n\t\t\tfmt.Printf(\"Goroutine %s Down\\n\", name)\n\t\t\treturn\n\t\t}\n\n\t\t// Increment the value and send it\n\t\t// over the channel.\n\t\tshare \u003c- (value + 1)\n\t}\n}\n","Hash":"cTRhf/5zDFPSHBvh6euG4nFGVE8="},{"Name":"exercise2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program that uses a fan out pattern to generate 100 random numbers\n// concurrently. Have each goroutine generate a single random number and return\n// that number to the main goroutine over a buffered channel. Set the size of\n// the buffered channel so no send ever blocks. Don't allocate more capacity\n// than you need. Have the main goroutine store each random number it receives\n// in a slice. Print the slice values then terminate the program.\npackage main\n\n// Add imports.\n\n// Declare constant for number of goroutines.\n\nfunc init() {\n\t// Seed the random number generator.\n}\n\nfunc main() {\n\n\t// Create the buffered channel with room for\n\t// each goroutine to be created.\n\n\t// Iterate and launch each goroutine.\n\t{\n\n\t\t// Create an anonymous function for each goroutine that\n\t\t// generates a random number and sends it on the channel.\n\t}\n\n\t// Create a variable to be used to track received messages.\n\t// Set the value to the number of goroutines created.\n\n\t// Iterate receiving each value until they are all received.\n\t// Store them in a slice of ints.\n\n\t// Print the values in our slice.\n}\n","Hash":"CRrdSwrGYzSv/p8ZixyEhoC745c="},{"Name":"answer2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program that uses a fan out pattern to generate 100 random numbers\n// concurrently. Have each goroutine generate a single random number and return\n// that number to the main goroutine over a buffered channel. Set the size of\n// the buffer channel so no send every blocks. Don't allocate more buffers than\n// you need. Have the main goroutine display each random number is receives and\n// then terminate the program.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nconst (\n\tgoroutines = 100\n)\n\nfunc main() {\n\n\t// Create the buffer channel with a buffer for\n\t// each goroutine to be created.\n\tvalues := make(chan int, goroutines)\n\n\t// Iterate and launch each goroutine.\n\tfor gr := 0; gr \u003c goroutines; gr++ {\n\n\t\t// Create an anonymous function for each goroutine that\n\t\t// generates a random number and sends it on the channel.\n\t\tgo func() {\n\t\t\tvalues \u003c- rand.Intn(1000)\n\t\t}()\n\t}\n\n\t// Create a variable to be used to track received messages.\n\t// Set the value to the number of goroutines created.\n\twait := goroutines\n\n\t// Iterate receiving each value until they are all received.\n\t// Store them in a slice of ints.\n\tvar nums []int\n\tfor wait \u003e 0 {\n\t\tnums = append(nums, \u003c-values)\n\t\twait--\n\t}\n\n\t// Print the values in our slice.\n\tfmt.Println(nums)\n}\n","Hash":"6/yRcdk/gFmoqpm88tUBFTsW9Tw="},{"Name":"exercise3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program that uses goroutines to generate up to 100 random numbers.\n// Do not send values that are divisible by 2. Have the main goroutine receive\n// values and add them to a slice.\npackage main\n\n// Declare constant for number of goroutines.\nconst goroutines = 100\n\nfunc init() {\n\t// Seed the random number generator.\n}\n\nfunc main() {\n\n\t// Create the channel for sharing results.\n\n\t// Create a sync.WaitGroup to monitor the Goroutine pool. Add the count.\n\n\t// Iterate and launch each goroutine.\n\t{\n\n\t\t// Create an anonymous function for each goroutine.\n\t\t{\n\n\t\t\t// Ensure the waitgroup is decremented when this function returns.\n\n\t\t\t// Generate a random number up to 1000.\n\n\t\t\t// Return early if the number is even. (n%2 == 0)\n\n\t\t\t// Send the odd values through the channel.\n\t\t}\n\t}\n\n\t// Create a goroutine that waits for the other goroutines to finish then\n\t// closes the channel.\n\n\t// Receive from the channel until it is closed.\n\t// Store values in a slice of ints.\n\n\t// Print the values in our slice.\n}\n","Hash":"yiRyIkxw6MOZSea3uragZF33zVs="},{"Name":"answer3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program that uses goroutines to generate up to 100 random numbers.\n// Do not send values that are divisible by 2. Have the main goroutine receive\n// values and add them to a slice.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\nconst (\n\tgoroutines = 100\n)\n\nfunc main() {\n\n\t// Create the channel for sharing results.\n\tvalues := make(chan int)\n\n\t// Create a sync.WaitGroup to monitor the Goroutine pool. Add the count.\n\tvar wg sync.WaitGroup\n\twg.Add(goroutines)\n\n\t// Iterate and launch each goroutine.\n\tfor gr := 0; gr \u003c goroutines; gr++ {\n\n\t\t// Create an anonymous function for each goroutine.\n\t\tgo func() {\n\n\t\t\t// Ensure the waitgroup is decremented when this function returns.\n\t\t\tdefer wg.Done()\n\n\t\t\t// Generate a random number up to 1000.\n\t\t\tn := rand.Intn(1000)\n\n\t\t\t// Return early if the number is divisible by 2. n%2 == 0\n\t\t\tif n%2 == 0 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Send the odd values through the channel.\n\t\t\tvalues \u003c- n\n\t\t}()\n\t}\n\n\t// Create a goroutine that waits for the other goroutines to finish then\n\t// closes the channel.\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(values)\n\t}()\n\n\t// Receive from the channel until it is closed.\n\t// Store values in a slice of ints.\n\tvar nums []int\n\tfor n := range values {\n\t\tnums = append(nums, n)\n\t}\n\n\t// Print the values in our slice.\n\tfmt.Printf(\"Result count: %d\\n\", len(nums))\n\tfmt.Println(nums)\n}\n","Hash":"hmE+PyxgRxNB43Ym9oaHduNbLdA="},{"Name":"exercise4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program that creates a fixed set of workers to generate random\n// numbers. Discard any number divisible by 2. Continue receiving until 100\n// numbers are received. Tell the workers to shut down before terminating.\npackage main\n\n// Add imports.\n\nfunc main() {\n\n\t// Create the channel for sharing results.\n\n\t// Create a channel \"shutdown\" to tell goroutines when to terminate.\n\n\t// Define the size of the worker pool. Use runtime.GOMAXPROCS(0) to size the pool based on number of processors.\n\n\t// Create a sync.WaitGroup to monitor the Goroutine pool. Add the count.\n\n\t// Create a fixed size pool of goroutines to generate random numbers.\n\t{\n\t\t{\n\n\t\t\t// Start an infinite loop.\n\t\t\t{\n\n\t\t\t\t// Generate a random number up to 1000.\n\n\t\t\t\t// Use a select to either send the number or receive the shutdown signal.\n\t\t\t\t{\n\n\t\t\t\t\t// In one case send the random number.\n\n\t\t\t\t\t// In another case receive from the shutdown channel.\n\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Create a slice to hold the random numbers.\n\n\t// Receive from the values channel with range.\n\t{\n\n\t\t// continue the loop if the value was even.\n\n\t\t// Store the odd number.\n\n\t\t// break the loop once we have 100 results.\n\t}\n\n\t// Send the shutdown signal by closing the shutdown channel.\n\n\t// Wait for the Goroutines to finish.\n\n\t// Print the values in our slice.\n}\n","Hash":"1VqjJFwcqfrYxq1Dgtn9DPWb4o4="},{"Name":"answer4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Write a program that creates a fixed set of workers to generate random\n// numbers. Discard any number divisible by 2. Continue receiving until 100\n// numbers are received. Tell the workers to shut down before terminating.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"runtime\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\t// Create the channel for sharing results.\n\tvalues := make(chan int)\n\n\t// Create a channel \"shutdown\" to tell goroutines when to terminate.\n\tshutdown := make(chan struct{})\n\n\t// Define the size of the worker pool. Use runtime.GOMAXPROCS(0) to size the pool based on number of processors.\n\tpoolSize := runtime.GOMAXPROCS(0)\n\n\t// Create a sync.WaitGroup to monitor the Goroutine pool. Add the count.\n\tvar wg sync.WaitGroup\n\twg.Add(poolSize)\n\n\t// Create a fixed size pool of goroutines to generate random numbers.\n\tfor i := 0; i \u003c poolSize; i++ {\n\t\tgo func(id int) {\n\n\t\t\t// Start an infinite loop.\n\t\t\tfor {\n\n\t\t\t\t// Generate a random number up to 1000.\n\t\t\t\tn := rand.Intn(1000)\n\n\t\t\t\t// Use a select to either send the number or receive the shutdown signal.\n\t\t\t\tselect {\n\n\t\t\t\t// In one case send the random number.\n\t\t\t\tcase values \u003c- n:\n\t\t\t\t\tfmt.Printf(\"Worker %d sent %d\\n\", id, n)\n\n\t\t\t\t// In another case receive from the shutdown channel.\n\t\t\t\tcase \u003c-shutdown:\n\t\t\t\t\tfmt.Printf(\"Worker %d shutting down\\n\", id)\n\t\t\t\t\twg.Done()\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}(i)\n\t}\n\n\t// Create a slice to hold the random numbers.\n\tvar nums []int\n\tfor i := range values {\n\n\t\t// continue the loop if the value was even.\n\t\tif i%2 == 0 {\n\t\t\tfmt.Println(\"Discarding\", i)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Store the odd number.\n\t\tfmt.Println(\"Keeping\", i)\n\t\tnums = append(nums, i)\n\n\t\t// break the loop once we have 100 results.\n\t\tif len(nums) == 100 {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Send the shutdown signal by closing the channel.\n\tfmt.Println(\"Receiver sending shutdown signal\")\n\tclose(shutdown)\n\n\t// Wait for the Goroutines to finish.\n\twg.Wait()\n\n\t// Print the values in our slice.\n\tfmt.Printf(\"Result count: %d\\n\", len(nums))\n\tfmt.Println(nums)\n}\n","Hash":"2pnwFjEAhDq+xR9mN8jXCdZma6s="}]}]} ,"embedding":{"Title":"Incorporação","Description":"A incorporação de tipos fornece a parte final de compartilhamento e reutilização de estado e comportamento entre tipos.","Pages":[{"Title":"Incorporação","Content":"\n \u003ch2\u003eIncorporação\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de assistência financeira, use nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudo\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n A incorporação de tipos fornece a parte final de compartilhamento e reutilização de \n\n\n estado e comportamento entre tipos. Através do uso da promoção do tipo interno, \n\n\n os campos e métodos de um tipo interno podem ser acessados diretamente por referências do tipo externo.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declarando Campos\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Tipos de incorporação\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Tipos e interfaces incorporados\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Implementações de interface de tipo externo e interno\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eFuncionamento da Incorporação\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este primeiro exemplo não mostra incorporação, apenas a declaração de dois tipos struct trabalhando juntos como um campo de um tipo para outro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n email string\n}\n\ntype admin struct {\n person user // NOT Embedding\n level string\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Isso é incorporação.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n email string\n}\n\ntype admin struct {\n user // Value Semantic Embedding\n level string\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O campo person é removido e resta apenas o nome do tipo. Você também pode incorporar um tipo usando a semântica de ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n email string\n}\n\ntype admin struct {\n *user // Pointer Semantic Embedding\n level string\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste caso, o ponteiro do tipo é incorporado. Em ambos os casos, o acesso ao valor incorporado é feito através do uso do nome do tipo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A melhor maneira de pensar sobre a incorporação é ver o tipo \u003ccode\u003euser\u003c/code\u003e como um tipo interno e o tipo\n\n\n \u003ccode\u003eadmin\u003c/code\u003e como um tipo externo. É essa relação de tipo interno/externo que é a mágica,\n\n\n pois com a incorporação, tudo relacionado ao tipo interno (tanto campos quanto métodos)\n\n\n pode ser promovido para o tipo externo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n email string\n}\n\nfunc (u *user) notify() {\n fmt.Printf(\u0026#34;Sending user email To %s\u0026lt;%s\u0026gt;\\n\u0026#34;,\n u.name,\n u.email)\n}\n\ntype admin struct {\n *user // Pointer Semantic Embedding\n level string\n}\n\nfunc main() {\n ad := admin{\n user: \u0026amp;user{\n name: \u0026#34;john smith\u0026#34;,\n email: \u0026#34;john@yahoo.com\u0026#34;,\n },\n level: \u0026#34;super\u0026#34;,\n }\n\n ad.user.notify()\n ad.notify() // Outer type promotion\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eSending user email To john smith\u0026lt;john@yahoo.com\u0026gt;\nSending user email To john smith\u0026lt;john@yahoo.com\u0026gt;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Depois de adicionar um método chamado \u003ccode\u003enotify\u003c/code\u003e para o tipo \u003ccode\u003euser\u003c/code\u003e e, em seguida, uma pequena função \u003ccode\u003emain\u003c/code\u003e.\n\n\n Você pode ver que a saída é a mesma, quer você chame o método \u003ccode\u003enotify\u003c/code\u003e diretamente através do valor do ponteiro interno \n\n\n ou através do valor do tipo externo. O método \u003ccode\u003enotify\u003c/code\u003e declarado para o tipo \u003ccode\u003euser\u003c/code\u003e é acessível diretamente pelo valor do tipo \u003ccode\u003eadmin\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Embora isso pareça herança, você deve ter cuidado. Isso não se trata de reutilizar estado, mas de promover comportamento.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype notifier interface {\n notify()\n}\n\nfunc sendNotification(n notifier) {\n n.notify()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Agora, você adiciona uma interface e uma função polimórfica que aceita qualquer valor concreto\n\n\n que implementa o conjunto completo de métodos de comportamento definidos pela interface \u003ccode\u003enotifier\u003c/code\u003e.\n\n\n Que é apenas um método chamado \u003ccode\u003enotify\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Devido à incorporação e à promoção, os valores do tipo \u003ccode\u003eadmin\u003c/code\u003e agora implementam a interface \u003ccode\u003enotifier\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n ad := admin{\n user: \u0026amp;user{\n name: \u0026#34;john smith\u0026#34;,\n email: \u0026#34;john@yahoo.com\u0026#34;,\n },\n level: \u0026#34;super\u0026#34;,\n }\n\n sendNotification(\u0026amp;ad)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eSending user email To john smith\u0026lt;john@yahoo.com\u0026gt;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode enviar o endereço do valor do tipo \u003ccode\u003eadmin\u003c/code\u003e para a função polimórfica, \n\n\n uma vez que a incorporação promove o comportamento \u003ccode\u003enotify\u003c/code\u003e até o tipo \u003ccode\u003eadmin\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype admin struct {\n *user // Pointer Semantic Embedding\n level string\n}\n\nfunc (a *admin) notify() {\n fmt.Printf(\u0026#34;Sending admin Email To %s\u0026lt;%s\u0026gt;\\n\u0026#34;,\n a.name,\n a.email)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando o tipo externo implementa um método que já foi implementado \n\n\n pelo tipo interno, a promoção não ocorre.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n ad := admin{\n user: \u0026amp;user{\n name: \u0026#34;john smith\u0026#34;,\n email: \u0026#34;john@yahoo.com\u0026#34;,\n },\n level: \u0026#34;super\u0026#34;,\n }\n\n sendNotification(\u0026amp;ad)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eSending admin email To john smith\u0026lt;john@yahoo.com\u0026gt;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode observar que o método do tipo externo está sendo executado agora.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eTipos incorporados nos permitem compartilhar estado ou comportamento entre tipos.\u003c/li\u003e\n \n \u003cli\u003eO tipo interno nunca perde sua identidade.\u003c/li\u003e\n \n \u003cli\u003eIsso não é herança.\u003c/li\u003e\n \n \u003cli\u003eAtravés da promoção, campos e métodos do tipo interno podem ser acessados através do tipo externo.\u003c/li\u003e\n \n \u003cli\u003eO tipo externo pode substituir o comportamento do tipo interno.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/05/methods-interfaces-and-embedded-types.html\" target=\"_blank\"\u003eMethods, Interfaces and Embedded Types in Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://rakyll.org/typesystem/\" target=\"_blank\"\u003eEmbedding is not inheritance\u003c/a\u003e - JBD \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how what we are doing is NOT embedding\n// a type but just using a type as a field.\npackage main\n\nimport \"fmt\"\n\n// user defines a user in the program.\ntype user struct {\n\tname string\n\temail string\n}\n\n// notify implements a method notifies users\n// of different events.\nfunc (u *user) notify() {\n\tfmt.Printf(\"Sending user email To %s\u003c%s\u003e\\n\",\n\t\tu.name,\n\t\tu.email)\n}\n\n// admin represents an admin user with privileges.\ntype admin struct {\n\tperson user // NOT Embedding\n\tlevel string\n}\n\nfunc main() {\n\n\t// Create an admin user.\n\tad := admin{\n\t\tperson: user{\n\t\t\tname: \"john smith\",\n\t\t\temail: \"john@yahoo.com\",\n\t\t},\n\t\tlevel: \"super\",\n\t}\n\n\t// We can access fields methods.\n\tad.person.notify()\n}\n","Hash":"TrXNd5apot5h5BLYcyFb+rTOGlU="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to embed a type into another type and\n// the relationship between the inner and outer type.\npackage main\n\nimport \"fmt\"\n\n// user defines a user in the program.\ntype user struct {\n\tname string\n\temail string\n}\n\n// notify implements a method notifies users\n// of different events.\nfunc (u *user) notify() {\n\tfmt.Printf(\"Sending user email To %s\u003c%s\u003e\\n\",\n\t\tu.name,\n\t\tu.email)\n}\n\n// admin represents an admin user with privileges.\ntype admin struct {\n\tuser // Embedded Type\n\tlevel string\n}\n\nfunc main() {\n\n\t// Create an admin user.\n\tad := admin{\n\t\tuser: user{\n\t\t\tname: \"john smith\",\n\t\t\temail: \"john@yahoo.com\",\n\t\t},\n\t\tlevel: \"super\",\n\t}\n\n\t// We can access the inner type's method directly.\n\tad.user.notify()\n\n\t// The inner type's method is promoted.\n\tad.notify()\n}\n","Hash":"JQHlNx98Dn6sxAy63T7Ht1LvcHM="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how embedded types work with interfaces.\npackage main\n\nimport \"fmt\"\n\n// notifier is an interface that defined notification\n// type behavior.\ntype notifier interface {\n\tnotify()\n}\n\n// user defines a user in the program.\ntype user struct {\n\tname string\n\temail string\n}\n\n// notify implements a method notifies users\n// of different events.\nfunc (u *user) notify() {\n\tfmt.Printf(\"Sending user email To %s\u003c%s\u003e\\n\",\n\t\tu.name,\n\t\tu.email)\n}\n\n// admin represents an admin user with privileges.\ntype admin struct {\n\tuser\n\tlevel string\n}\n\nfunc main() {\n\n\t// Create an admin user.\n\tad := admin{\n\t\tuser: user{\n\t\t\tname: \"john smith\",\n\t\t\temail: \"john@yahoo.com\",\n\t\t},\n\t\tlevel: \"super\",\n\t}\n\n\t// Send the admin user a notification.\n\t// The embedded inner type's implementation of the\n\t// interface is \"promoted\" to the outer type.\n\tsendNotification(\u0026ad)\n}\n\n// sendNotification accepts values that implement the notifier\n// interface and sends notifications.\nfunc sendNotification(n notifier) {\n\tn.notify()\n}\n","Hash":"s11QYi8CSucrfvdwng/+d2bUbWg="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show what happens when the outer and inner\n// type implement the same interface.\npackage main\n\nimport \"fmt\"\n\n// notifier is an interface that defined notification\n// type behavior.\ntype notifier interface {\n\tnotify()\n}\n\n// user defines a user in the program.\ntype user struct {\n\tname string\n\temail string\n}\n\n// notify implements a method notifies users\n// of different events.\nfunc (u *user) notify() {\n\tfmt.Printf(\"Sending user email To %s\u003c%s\u003e\\n\",\n\t\tu.name,\n\t\tu.email)\n}\n\n// admin represents an admin user with privileges.\ntype admin struct {\n\tuser\n\tlevel string\n}\n\n// notify implements a method notifies admins\n// of different events.\nfunc (a *admin) notify() {\n\tfmt.Printf(\"Sending admin Email To %s\u003c%s\u003e\\n\",\n\t\ta.name,\n\t\ta.email)\n}\n\nfunc main() {\n\n\t// Create an admin user.\n\tad := admin{\n\t\tuser: user{\n\t\t\tname: \"john smith\",\n\t\t\temail: \"john@yahoo.com\",\n\t\t},\n\t\tlevel: \"super\",\n\t}\n\n\t// Send the admin user a notification.\n\t// The embedded inner type's implementation of the\n\t// interface is NOT \"promoted\" to the outer type.\n\tsendNotification(\u0026ad)\n\n\t// We can access the inner type's method directly.\n\tad.user.notify()\n\n\t// The inner type's method is NOT promoted.\n\tad.notify()\n}\n\n// sendNotification accepts values that implement the notifier\n// interface and sends notifications.\nfunc sendNotification(n notifier) {\n\tn.notify()\n}\n","Hash":"auEPqH4SvHwZ/Ygfcj1VmnYyLWo="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Utilize o template como ponto de partida para concluir os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Edite o código a partir do template. Adicione um novo tipo chamado \u003ccode\u003eCachingFeed\u003c/code\u003e \n\n\n que incorpora \u003ccode\u003eFeed\u003c/code\u003e e substitui o método \u003ccode\u003eFetch\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This program defines a type Feed with two methods: Count and Fetch. Create a\n// new type CachingFeed that embeds *Feed but overrides the Fetch method.\n//\n// The CachingFeed type should have a map of Documents to limit the number of\n// calls to Feed.Fetch.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n)\n\n// Document is the core data model we are working with.\ntype Document struct {\n\tKey string\n\tTitle string\n}\n\n// ==================================================\n\n// Feed is a type that knows how to fetch Documents.\ntype Feed struct{}\n\n// Count tells how many documents are in the feed.\nfunc (f *Feed) Count() int {\n\treturn 42\n}\n\n// Fetch simulates looking up the document specified by key. It is slow.\nfunc (f *Feed) Fetch(key string) (Document, error) {\n\ttime.Sleep(time.Second)\n\n\tdoc := Document{\n\t\tKey: key,\n\t\tTitle: \"Title for \" + key,\n\t}\n\treturn doc, nil\n}\n\n// ==================================================\n\n// FetchCounter is the behavior we depend on for our process function.\ntype FetchCounter interface {\n\tFetch(key string) (Document, error)\n\tCount() int\n}\n\nfunc process(fc FetchCounter) {\n\tfmt.Printf(\"There are %d documents\\n\", fc.Count())\n\n\tkeys := []string{\"a\", \"a\", \"a\", \"b\", \"b\", \"b\"}\n\n\tfor _, key := range keys {\n\t\tdoc, err := fc.Fetch(key)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Could not fetch %s : %v\", key, err)\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Printf(\"%s : %v\\n\", key, doc)\n\t}\n}\n\n// ==================================================\n\n// CachingFeed keeps a local copy of Documents that have already been\n// retrieved. It embeds Feed to get the Fetch and Count behavior but\n// \"overrides\" Fetch to have its cache.\ntype CachingFeed struct {\n\t// TODO embed *Feed and add a field for a map[string]Document.\n}\n\n// NewCachingFeed initializes a CachingFeed for use.\nfunc NewCachingFeed(f *Feed) *CachingFeed {\n\n\t// TODO create a CachingFeed with an initialized map and embedded feed.\n\t// Return its address.\n\n\treturn nil // Remove this line.\n}\n\n// Fetch calls the embedded type's Fetch method if the key is not cached.\nfunc (cf *CachingFeed) Fetch(key string) (Document, error) {\n\n\t// TODO implement this method. Check the map field for the specified key and\n\t// return it if found. If it's not found, call the embedded types Fetch\n\t// method. Store the result in the map before returning it.\n\n\treturn Document{}, nil // Remove this line.\n}\n\n// ==================================================\n\nfunc main() {\n\tfmt.Println(\"Using Feed directly\")\n\tprocess(\u0026Feed{})\n\n\t// Call process again with your CachingFeed.\n\t//fmt.Println(\"Using CachingFeed\")\n}\n","Hash":"AcSdLzJaPy03h731V6kEO+REJgc="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how you can use embedding to reuse behavior from\n// another type and override specific methods.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n)\n\n// Document is the core data model we are working with.\ntype Document struct {\n\tKey string\n\tTitle string\n}\n\n// ==================================================\n\n// Feed is a type that knows how to fetch Documents.\ntype Feed struct{}\n\n// Count tells how many documents are in the feed.\nfunc (f *Feed) Count() int {\n\treturn 42\n}\n\n// Fetch simulates looking up the document specified by key. It is slow.\nfunc (f *Feed) Fetch(key string) (Document, error) {\n\ttime.Sleep(time.Second)\n\n\tdoc := Document{\n\t\tKey: key,\n\t\tTitle: \"Title for \" + key,\n\t}\n\treturn doc, nil\n}\n\n// ==================================================\n\n// CachingFeed keeps a local copy of Documents that have already been\n// retrieved. It embeds Feed to get the Fetch and Count behavior but\n// \"overrides\" Fetch to have its cache.\ntype CachingFeed struct {\n\tdocs map[string]Document\n\t*Feed\n}\n\n// NewCachingFeed initializes a CachingFeed for use.\nfunc NewCachingFeed(f *Feed) *CachingFeed {\n\treturn \u0026CachingFeed{\n\t\tdocs: make(map[string]Document),\n\t\tFeed: f,\n\t}\n}\n\n// Fetch calls the embedded type's Fetch method if the key is not cached.\nfunc (cf *CachingFeed) Fetch(key string) (Document, error) {\n\tif doc, ok := cf.docs[key]; ok {\n\t\treturn doc, nil\n\t}\n\n\tdoc, err := cf.Feed.Fetch(key)\n\tif err != nil {\n\t\treturn Document{}, err\n\t}\n\n\tcf.docs[key] = doc\n\treturn doc, nil\n}\n\n// ==================================================\n\n// FetchCounter is the behavior we depend on for our process function.\ntype FetchCounter interface {\n\tFetch(key string) (Document, error)\n\tCount() int\n}\n\nfunc process(fc FetchCounter) {\n\tfmt.Printf(\"There are %d documents\\n\", fc.Count())\n\n\tkeys := []string{\"a\", \"a\", \"a\", \"b\", \"b\", \"b\"}\n\n\tfor _, key := range keys {\n\t\tdoc, err := fc.Fetch(key)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Could not fetch %s : %v\", key, err)\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Printf(\"%s : %v\\n\", key, doc)\n\t}\n}\n\nfunc main() {\n\tfmt.Println(\"Using Feed directly\")\n\tprocess(\u0026Feed{})\n\n\tfmt.Println(\"Using CachingFeed\")\n\tc := NewCachingFeed(\u0026Feed{})\n\tprocess(c)\n}\n","Hash":"RkxU0OGU2rNjofexQd50IYkOab0="}]}]} ,"functions":{"Title":"Funções","Description":"Funções estão no núcleo da linguagem e fornecem um mecanismo para agrupar e organizar nosso código em partes separadas e distintas de funcionalidade.","Pages":[{"Title":"Funções","Content":"\n \u003ch2\u003eFunções\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Funções estão no núcleo da linguagem e fornecem um mecanismo para agrupar e\n\n\n organizar nosso código em partes separadas e distintas de funcionalidade. Elas\n\n\n podem ser usadas para fornecer uma API para os pacotes que escrevemos e são um\n\n\n componente central para a concorrência.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Funções em Go desempenham um papel central na estruturação do código, promovendo\n\n\n um código limpo, de fácil manutenção, e eficiente. Entender como declarar, definir\n\n\n e usar funções é crucial para escrever programas eficazes em Go.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Retornar múltiplos valores\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Blank identifier\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Redeclarações\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Funções Anônimas/Closures\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Recover panics\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n \n \u003cp\u003e\n Funções são um bloco de construção fundamental dos programas e são usadas para encapsular\n\n\n e organizar o código para melhor modularidade e reutilização. Funções são blocos de código\n\n\n que executam uma tarefa específica ou um conjunto de tarefas relacionadas. Aqui está uma\n\n\n visão geral das funções em Go:\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eDeclarando Funções\u003c/h2\u003e\n \n \n \u003cp\u003e\n Para declarar uma função em Go, usa-se a palavra-chave \u003ccode\u003efunc\u003c/code\u003e seguida\n\n\n do nome da função, uma lista de parâmetros entre parênteses e opcionalmente\n\n\n um tipo a ser retornado. A sintaxe geral é:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc functionName(parameter1 type, parameter2 type, ...) return_type {\n // Function body\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Por exemplo:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc add(x int, y int) int {\n return x \u0026#43; y\n}\u003c/pre\u003e\n \n\n\n \u003ch2\u003eParâmetros e Valores de Retorno\u003c/h2\u003e\n \n \n \u003cp\u003e\n Funções podem receber zero ou mais parâmetros, que são os valores passados para\n\n\n a função quando ela é chamada. Cada parâmetro consiste de um nome e um tipo. No\n\n\n exemplo acima, \u003ccode\u003eadd\u003c/code\u003e recebe dois parâmetros inteiros, \u003ccode\u003ex\u003c/code\u003e e \u003ccode\u003ey\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Funções podem retornar um ou mais valores (ou nenhum, nesse caso, você pode omitir\n\n\n o tipo de retorno). A instrução \u003ccode\u003ereturn\u003c/code\u003e é usada para especificar o valor a ser retornado.\n\n\n No exemplo acima, \u003ccode\u003eadd\u003c/code\u003e retorna um inteiro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Go permite que funções retornem múltiplos valores. Isso é útil em casos que você\n\n\n quer retornar mais de um resultado em uma função. Por exemplo:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc divide(x, y float64) (float64, error) {\n if y == 0 {\n return 0, errors.New(\u0026#34;division by zero\u0026#34;)\n }\n return x / y, nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste exemplo, a função \u003ccode\u003edivide\u003c/code\u003e retorna um resultado de ponto flutuante e\n\n\n um erro (se ocorrer a divisão por zero).\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Go permite especificar nomes para os valores de retorno na assinatura de uma função.\n\n\n Os valores de retorno nomeados são inicializados automaticamente e podem ser usados\n\n\n como variáveis normais dentro da função. Eles são particularmente úteis ao lidar\n\n\n com funções complexas ou no tratamento de erros. Por exemplo:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc divide(x, y float64) (result float64, err error) {\n if y == 0 {\n err = errors.New(\u0026#34;division by zero\u0026#34;)\n return\n }\n result = x / y\n return\n}\u003c/pre\u003e\n \n\n\n \u003ch2\u003eChamando Funções\u003c/h2\u003e\n \n \n \u003cp\u003e\n Para chamar uma função em Go, usa-se o nome da função seguido por uma lista de\n\n\n argumentos entre parênteses. Se a função tiver múltiplos valores de retorno, você\n\n\n poderá capturá-los em variáveis. Por exemplo:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003esum := add(3, 5) // Call the add function and assign its result to sum\nresult, err := divide(8, 2) // Call the divide function and capture both result and error\u003c/pre\u003e\n \n\n\n \u003ch2\u003eVariadic Parameters em Funções\u003c/h2\u003e\n \n \n \u003cp\u003e\n Go suporta variadic functions, que permitem passar um número variável de\n\n\n argumentos para uma função. Para definir um variadic parameter, utiliza-se\n\n\n reticências (\u003ccode\u003e...\u003c/code\u003e) seguidas do tipo do parâmetro. Por exemplo:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc calculateSum(nums ...int) int {\n sum := 0\n for _, num := range nums {\n sum \u0026#43;= num\n }\n return sum\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode chamar essa função com quantos inteiros quiser.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eFunções Anônimas\u003c/h2\u003e\n \n \n \u003cp\u003e\n Go suporta funções anônimas, também conhecidas como closures. Estas são funções\n\n\n sem nome e podem ser atribuídas a variáveis e usadas com argumentos para outras\n\n\n funções. Closures são frequentemente usadas em Go para tarefas como definir\n\n\n funções inline ou para programação concorrente usando goroutines.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eadd := func(x, y int) int {\n return x \u0026#43; y\n}\n\nresult := add(3, 5)\u003c/pre\u003e\n \n\n\n \u003ch2\u003eFunção Como Um Tipo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Em Go, funções também podem ser usadas como tipos. Isso permite que você defina\n\n\n funções que recebem outras funções como argumento ou as retorne como resultado.\n\n\n Esse é um recurso poderoso para implementar funções de ordem superior ou callbacks.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype MathFunc func(int, int) int\n\nfunc operate(x, y int, op MathFunc) int {\n return op(x, y)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode passar funções como argumento de \u003ccode\u003eoperate\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eDefer e Panic\u003c/h2\u003e\n \n \n \u003cp\u003e\n Go fornece duas funções built-in especiais chamadas \u003ccode\u003edefer\u003c/code\u003e e \u003ccode\u003epanic\u003c/code\u003e para lidar\n\n\n com situações excepcionais e gerenciamento de recursos. \u003ccode\u003edefer\u003c/code\u003e é usada para agendar\n\n\n uma chamada de função para ser executada logo antes do retorno da função, enquanto \u003ccode\u003epanic\u003c/code\u003e\n\n\n é usada para acionar um erro em tempo de execução e fazer o unwind da stack.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eFunções podem retornar múltiplos valores e a maioria retorna um valor de erro.\u003c/li\u003e\n \n \u003cli\u003eO valor de erro deve sempre ser checado como parte da lógica de programação.\u003c/li\u003e\n \n \u003cli\u003eO blank identifier pode ser usado para ignorar valores.\u003c/li\u003e\n \n \u003cli\u003eSintaxe: func, receiver, nome, [parâmetro(s)], [retorno(s)], bloco de código.\u003c/li\u003e\n \n \u003cli\u003eVariadic parameters, variadic arguments, e desdobramento de slice.\u003c/li\u003e\n \n \u003cli\u003eFunções são um tipo: você pode usar funções como parâmetros, argumentos, \u0026amp; retornos.\u003c/li\u003e\n \n \u003cli\u003eDefer é usado para agendar uma chamada de função em uma outra função.\u003c/li\u003e\n \n \u003cli\u003ePanic aciona um erro em tempo de execução e faz o unwind da stack.\u003c/li\u003e\n \n \u003cli\u003eRetornos nomeados são menos legíveis e não são idiomáticos.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/doc/effective_go.html#functions\" target=\"_blank\"\u003eEffective Go\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/10/functions-and-naked-returns-in-go.html\" target=\"_blank\"\u003eFunctions and Naked returns in Go\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/06/understanding-defer-panic-and-recover.html\" target=\"_blank\"\u003eUnderstanding defer panics and recover\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how functions can return multiple values while using\n// named and struct types.\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// user is a struct type that declares user information.\ntype user struct {\n\tID int\n\tName string\n}\n\nfunc main() {\n\n\t// Retrieve the user profile.\n\tu, err := retrieveUser(\"sally\")\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\t// Display the user profile.\n\tfmt.Printf(\"%+v\\n\", *u)\n}\n\n// retrieveUser retrieves the user document for the specified\n// user and returns a pointer to a user type value.\nfunc retrieveUser(name string) (*user, error) {\n\n\t// Make a call to get the user in a json response.\n\tr, err := getUser(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Unmarshal the json document into a value of\n\t// the user struct type.\n\tvar u user\n\terr = json.Unmarshal([]byte(r), \u0026u)\n\treturn \u0026u, err\n}\n\n// GetUser simulates a web call that returns a json\n// document for the specified user.\nfunc getUser(name string) (string, error) {\n\tresponse := `{\"id\":1432, \"name\":\"sally\"}`\n\treturn response, nil\n}\n","Hash":"JbgLG0slSV4XETLD96vydyV9p+w="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how we can use the blank identifier to\n// ignore return values.\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n)\n\n// user is a struct type that declares user information.\ntype user struct {\n\tID int\n\tName string\n}\n\n// updateStats provides update stats.\ntype updateStats struct {\n\tModified int\n\tDuration float64\n\tSuccess bool\n\tMessage string\n}\n\nfunc main() {\n\n\t// Declare and initialize a value of type user.\n\tu := user{\n\t\tID: 1432,\n\t\tName: \"Betty\",\n\t}\n\n\t// Update the user Name. Don't care about the update stats.\n\tif _, err := updateUser(\u0026u); err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\t// Display the update was Successful.\n\tfmt.Println(\"Updated user record for ID\", u.ID)\n}\n\n// updateUser updates the specified user document.\nfunc updateUser(u *user) (*updateStats, error) {\n\n\t// response simulates a JSON response.\n\tresponse := `{\"Modified\":1, \"Duration\":0.005, \"Success\" : true, \"Message\": \"updated\"}`\n\n\t// Unmarshal the json document into a value of\n\t// the userStats struct type.\n\tvar us updateStats\n\tif err := json.Unmarshal([]byte(response), \u0026us); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Check the update status to verify the update\n\t// was Successful.\n\tif us.Success != true {\n\t\treturn nil, errors.New(us.Message)\n\t}\n\n\treturn \u0026us, nil\n}\n","Hash":"hBSa06N0gn7y46K/PzculqcpFeo="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// From Spec:\n// a short variable declaration may redeclare variables provided they\n// were originally declared earlier in the same block with the same\n// type, and at least one of the non-blank variables is new.\n\n// Sample program to show some of the mechanics behind the\n// short variable declaration operator redeclares.\npackage main\n\nimport \"fmt\"\n\n// user is a struct type that declares user information.\ntype user struct {\n\tid int\n\tname string\n}\n\nfunc main() {\n\n\t// Declare the error variable.\n\tvar err1 error\n\n\t// The short variable declaration operator will\n\t// declare u and redeclare err1.\n\tu, err1 := getUser()\n\tif err1 != nil {\n\t\treturn\n\t}\n\n\tfmt.Println(u)\n\n\t// The short variable declaration operator will\n\t// redeclare u and declare err2.\n\tu, err2 := getUser()\n\tif err2 != nil {\n\t\treturn\n\t}\n\n\tfmt.Println(u)\n}\n\n// getUser returns a pointer of type user.\nfunc getUser() (*user, error) {\n\treturn \u0026user{1432, \"Betty\"}, nil\n}\n","Hash":"O7zksLUFIxYTNJ/qs+a6QmLGbrA="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how anonymous functions and closures work.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar n int\n\n\t// Declare an anonymous function and call it.\n\tfunc() {\n\t\tfmt.Println(\"Direct:\", n)\n\t}()\n\n\t// Declare an anonymous function and assign it to a variable.\n\tf := func() {\n\t\tfmt.Println(\"Variable:\", n)\n\t}\n\n\t// Call the anonymous function through the variable.\n\tf()\n\n\t// Defer the call to the anonymous function till after main returns.\n\tdefer func() {\n\t\tfmt.Println(\"Defer 1:\", n)\n\t}()\n\n\t// Set the value of n to 3 before the return.\n\tn = 3\n\n\t// Call the anonymous function through the variable.\n\tf()\n\n\t// Defer the call to the anonymous function till after main returns.\n\tdefer func() {\n\t\tfmt.Println(\"Defer 2:\", n)\n\t}()\n}\n","Hash":"wsliFjOgGCdhSuHhm1bQ1vWtOf4="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to recover from panics.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n)\n\nfunc main() {\n\n\t// Call the testPanic function to run the test.\n\tif err := testPanic(); err != nil {\n\t\tfmt.Println(\"Error:\", err)\n\t}\n}\n\n// testPanic simulates a function that encounters a panic to\n// test our catchPanic function.\nfunc testPanic() (err error) {\n\n\t// Schedule the catchPanic function to be called when\n\t// the testPanic function returns.\n\tdefer catchPanic(\u0026err)\n\n\tfmt.Println(\"Start Test\")\n\n\t// Mimic a traditional error from a function.\n\terr = mimicError(\"1\")\n\n\t// Trying to dereference a nil pointer will cause the\n\t// runtime to panic.\n\tvar p *int\n\t*p = 10\n\n\tfmt.Println(\"End Test\")\n\treturn err\n}\n\n// catchPanic catches panics and processes the error.\nfunc catchPanic(err *error) {\n\n\t// Check if a panic occurred.\n\tif r := recover(); r != nil {\n\t\tfmt.Println(\"PANIC Deferred\")\n\n\t\t// Capture the stack trace.\n\t\tbuf := make([]byte, 10000)\n\t\truntime.Stack(buf, false)\n\t\tfmt.Println(\"Stack Trace:\", string(buf))\n\n\t\t// If the caller wants the error back provide it.\n\t\tif err != nil {\n\t\t\t*err = fmt.Errorf(\"%v\", r)\n\t\t}\n\t}\n}\n\n// mimicError is a function that simulates an error for\n// testing the code.\nfunc mimicError(key string) error {\n\treturn fmt.Errorf(\"Mimic Error : %s\", key)\n}\n","Hash":"rHmk/7Zj+8L5IeBJj4OId/XaPKk="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo como um ponto de partida para completar os exercícios. Uma\n\n\n possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Declare um tipo struct para guardar informações sobre um user. Declare\n\n\n uma função que cria um valor de user e retorna um ponteiro para esse valor e um valor de erro.\n\n\n Chame essa função a partir da main e exiba o valor.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Faça uma segunda chamada para a sua função, mas desta vez ignore o valor\n\n\n e apenas teste o valor de erro.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct type to maintain information about a user. Declare a function\n// that creates value of and returns pointers of this type and an error value. Call\n// this function from main and display the value.\n//\n// Make a second call to your function but this time ignore the value and just test\n// the error value.\npackage main\n\n// Add imports.\n\n// Declare a type named user.\n\n// Declare a function that creates user type values and returns a pointer\n// to that value and an error value of nil.\nfunc funcName() /* (pointer return arg, error return arg) */ {\n\n\t// Create a value of type user and return the proper values.\n}\n\nfunc main() {\n\n\t// Use the function to create a value of type user. Check\n\t// the error being returned.\n\n\t// Display the value that the pointer points to.\n\n\t// Call the function again and just check the error.\n}\n","Hash":"5beNH5BwsJ+WMx2E2NTKV2ensQs="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct type to maintain information about a user. Declare a function\n// that creates value of and returns pointers of this type and an error value. Call\n// this function from main and display the value.\n//\n// Make a second call to your function but this time ignore the value and just test\n// the error value.\npackage main\n\nimport \"fmt\"\n\n// user represents a user in the system.\ntype user struct {\n\tname string\n\temail string\n}\n\n// newUser creates and returns pointers of user type values.\nfunc newUser() (*user, error) {\n\treturn \u0026user{\"Bill\", \"bill@ardanlabs.com\"}, nil\n}\n\nfunc main() {\n\n\t// Create a value of type user.\n\tu, err := newUser()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\t// Display the value.\n\tfmt.Println(*u)\n\n\t// Call the function and just check the error on the return.\n\t_, err = newUser()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n}\n","Hash":"XUzF6Juc7+11tOVF8EKkl+DPjfU="}]}]} ,"generics-behavior-constraints":{"Title":"Comportamento como Restrição","Description":"Cada tipo genérico requer uma restrição a ser declarada para que o compilador saiba quais substituições de tipos concretos ele pode aceitar ou rejeitar durante o tempo de compilação.","Pages":[{"Title":"Generics - Comportamento como Restrição","Content":"\n \u003ch2\u003eGenerics - Comportamento como Restrição\u003c/h2\u003e\n \n \n \u003cp\u003e\n Cada tipo genérico requer uma restrição a ser declarada para que o compilador saiba quais\n\n\n substituições de tipos concretos ele pode aceitar ou rejeitar durante o tempo de compilação.\n\n\n Isso é necessário mesmo que não haja uma restrição real sobre o que o tipo genérico pode ser,\n\n\n daí o identificador de restrição pré-declarado \u003ccode\u003eany\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Generics, que apresenta todos os exemplos desta seção do Tour.\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Função \u003ccode\u003estringify\u003c/code\u003e concreta\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2\u003c/b\u003e: Função \u003ccode\u003estringify\u003c/code\u003e com assertiva de tipo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3\u003c/b\u003e: Função \u003ccode\u003estringify\u003c/code\u003e com interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4\u003c/b\u003e: Função \u003ccode\u003estringify\u003c/code\u003e genérica\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicado\u003c/h2\u003e\n \n \n \u003cp\u003e\n Curiosamente, o conceito de uma restrição já existe na linguagem.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype User struct {\n name string\n}\n\nfunc (u User) String() string {\n return u.name\n}\n\ntype Stringer interface {\n String() string\n}\n\nfunc Concrete(u User) {\n u.String()\n}\n\nfunc Polymorphic(s Stringer) {\n s.String()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O código define um tipo concreto chamado \u003ccode\u003eUser\u003c/code\u003e e implementa um método chamado \u003ccode\u003eString\u003c/code\u003e que\n\n\n retorna o nome do usuário. Em seguida, é declarado um tipo de interface chamado \u003ccode\u003eStringer\u003c/code\u003e,\n\n\n que declara um comportamento chamado \u003ccode\u003eString\u003c/code\u003e, que retorna uma \u003ccode\u003estring\u003c/code\u003e. Graças ao método declarado para \u003ccode\u003eUser\u003c/code\u003e,\n\n\n é possível afirmar que o tipo concreto \u003ccode\u003eUser\u003c/code\u003e implementa a interface \u003ccode\u003eStringer\u003c/code\u003e usando semântica de valor.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A função \u003ccode\u003eConcrete\u003c/code\u003e é exatamente isso, uma função que aceita dados concretos com base no que são.\n\n\n A função \u003ccode\u003ePolymorphic\u003c/code\u003e também é assim, uma função que aceita dados concretos com base no que eles podem fazer.\n\n\n Esta é a principal diferença entre uma função concreta e uma função polimórfica. Uma está limitada a um tipo de dado,\n\n\n enquanto a outra não está. No entanto, existe uma restrição quanto aos dados concretos que podem ser passados para a função polimórfica.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A interface \u003ccode\u003eStringer\u003c/code\u003e define essa restrição ao declarar um conjunto de comportamentos que os dados\n\n\n concretos devem ser capazes de exibir. Quando aplicado como o tipo de entrada, o compilador pode garantir\n\n\n que a restrição comportamental seja cumprida todas as vezes que a função for chamada.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Existem funções genéricas que exigirão o mesmo tipo de restrição comportamental.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc stringify[T fmt.Stringer](slice []T) []string {\n ret := make([]string, 0, len(slice))\n \n for _, value := range slice {\n ret = append(ret, value.String())\n }\n \n return ret\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui está a função genérica \u003ccode\u003estringify\u003c/code\u003e. Ela aceita um \u003ccode\u003eslice\u003c/code\u003e de algum tipo T e retorna\n\n\n um \u003ccode\u003eslice\u003c/code\u003e de valores de \u003ccode\u003estring\u003c/code\u003e que contém uma versão em formato de \u003ccode\u003estring\u003c/code\u003e de cada valor da coleção\n\n\n de entrada. A chave para fazer essa função funcionar é a chamada do método \u003ccode\u003eString\u003c/code\u003e para cada valor do tipo T.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O problema é que o compilador precisa saber e verificar se os valores do tipo T realmente\n\n\n possuem um método chamado \u003ccode\u003eString\u003c/code\u003e. Quando o tipo genérico T é declarado, a interface \u003ccode\u003efmt.Stringer\u003c/code\u003e é\n\n\n fornecida como a restrição. O compilador agora sabe verificar qualquer substituição de tipo e dados\n\n\n sendo passados para a função quanto a esse conjunto de métodos de comportamento.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Isso é excelente porque a interface está sendo usada novamente para o mesmo propósito, e a linguagem não precisa de uma nova palavra-chave.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to implement a stringify function that is\n// specific to each of the concrete types implemented above. In each case,\n// the stringify function returns a slice of strings. These function use\n// the String method against the individual user or customer value.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc stringifyUsers(users []user) []string {\n\tret := make([]string, 0, len(users))\n\tfor _, user := range users {\n\t\tret = append(ret, user.String())\n\t}\n\treturn ret\n}\n\nfunc stringifyCustomers(customers []customer) []string {\n\tret := make([]string, 0, len(customers))\n\tfor _, customer := range customers {\n\t\tret = append(ret, customer.String())\n\t}\n\treturn ret\n}\n\n// Defining two types that implement the fmt.Stringer interface. Each\n// implementation creates a stringified version of the concrete type.\n\ntype user struct {\n\tname string\n\temail string\n}\n\nfunc (u user) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"user\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\ntype customer struct {\n\tname string\n\temail string\n}\n\nfunc (u customer) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"customer\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\n// =============================================================================\n\nfunc main() {\n\tusers := []user{\n\t\t{name: \"Bill\", email: \"bill@ardanlabs.com\"},\n\t\t{name: \"Ale\", email: \"ale@whatever.com\"},\n\t}\n\n\ts1 := stringifyUsers(users)\n\n\tfmt.Println(\"users:\", s1)\n\n\t// -------------------------------------------------------------------------\n\n\tcustomers := []customer{\n\t\t{name: \"Google\", email: \"you@google.com\"},\n\t\t{name: \"MSFT\", email: \"you@msft.com\"},\n\t}\n\n\ts2 := stringifyCustomers(customers)\n\n\tfmt.Println(\"customers:\", s2)\n}\n","Hash":"aY/Cji6nBdSLeK004zvpHJPtbPs="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to implement an empty interface solution which\n// uses type assertions for the different concrete slices to be supported.\n// We've basically moved the functions from above into case statements.\n// This function uses the String method against the value.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc stringifyAssert(v interface{}) []string {\n\tswitch list := v.(type) {\n\tcase []user:\n\t\tret := make([]string, 0, len(list))\n\t\tfor _, value := range list {\n\t\t\tret = append(ret, value.String())\n\t\t}\n\t\treturn ret\n\n\tcase []customer:\n\t\tret := make([]string, 0, len(list))\n\t\tfor _, value := range list {\n\t\t\tret = append(ret, value.String())\n\t\t}\n\t\treturn ret\n\t}\n\n\treturn nil\n}\n\n// Defining two types that implement the fmt.Stringer interface. Each\n// implementation creates a stringified version of the concrete type.\n\ntype user struct {\n\tname string\n\temail string\n}\n\nfunc (u user) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"user\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\ntype customer struct {\n\tname string\n\temail string\n}\n\nfunc (u customer) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"customer\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\n// =============================================================================\n\nfunc main() {\n\tusers := []user{\n\t\t{name: \"Bill\", email: \"bill@ardanlabs.com\"},\n\t\t{name: \"Ale\", email: \"ale@whatever.com\"},\n\t}\n\n\ts1 := stringifyAssert(users)\n\n\tfmt.Println(\"users:\", s1)\n\n\t// -------------------------------------------------------------------------\n\n\tcustomers := []customer{\n\t\t{name: \"Google\", email: \"you@google.com\"},\n\t\t{name: \"MSFT\", email: \"you@msft.com\"},\n\t}\n\n\ts2 := stringifyAssert(customers)\n\n\tfmt.Println(\"customers:\", s2)\n}\n","Hash":"0BsFmMunEiH0bZ3Khb3UXGSb3ks="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to implement a reflection solution which allows\n// a slice of any type to be provided and stringified. This is a generic\n// function thanks to the reflect package. Notice the call to the String\n// method via reflection.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\nfunc stringifyReflect(v interface{}) []string {\n\tval := reflect.ValueOf(v)\n\tif val.Kind() != reflect.Slice {\n\t\treturn nil\n\t}\n\n\tret := make([]string, 0, val.Len())\n\n\tfor i := 0; i \u003c val.Len(); i++ {\n\t\tm := val.Index(i).MethodByName(\"String\")\n\t\tif !m.IsValid() {\n\t\t\treturn nil\n\t\t}\n\n\t\tdata := m.Call(nil)\n\t\tret = append(ret, data[0].String())\n\t}\n\n\treturn ret\n}\n\n// Defining two types that implement the fmt.Stringer interface. Each\n// implementation creates a stringified version of the concrete type.\n\ntype user struct {\n\tname string\n\temail string\n}\n\nfunc (u user) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"user\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\ntype customer struct {\n\tname string\n\temail string\n}\n\nfunc (u customer) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"customer\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\n// =============================================================================\n\nfunc main() {\n\tusers := []user{\n\t\t{name: \"Bill\", email: \"bill@ardanlabs.com\"},\n\t\t{name: \"Ale\", email: \"ale@whatever.com\"},\n\t}\n\n\ts1 := stringifyReflect(users)\n\n\tfmt.Println(\"users:\", s1)\n\n\t// -------------------------------------------------------------------------\n\n\tcustomers := []customer{\n\t\t{name: \"Google\", email: \"you@google.com\"},\n\t\t{name: \"MSFT\", email: \"you@msft.com\"},\n\t}\n\n\ts2 := stringifyReflect(customers)\n\n\tfmt.Println(\"customers:\", s2)\n}\n","Hash":"vFVTlYOBPLHuigkJMbL0NUj4QwY="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to implement a generics solution which allows\n// a slice of some type T (to be determined later) to be passed and stringified.\n// This code more closely resembles the concrete implementations that we started\n// with and is easier to read than the reflect implementation. However, an\n// interface constraint of type fmt.Stringer is applied to allow the compiler\n// to know the value of type T passed requires a String method.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc stringify[T fmt.Stringer](slice []T) []string {\n\tret := make([]string, 0, len(slice))\n\n\tfor _, value := range slice {\n\t\tret = append(ret, value.String())\n\t}\n\n\treturn ret\n}\n\n// Defining two types that implement the fmt.Stringer interface. Each\n// implementation creates a stringified version of the concrete type.\n\ntype user struct {\n\tname string\n\temail string\n}\n\nfunc (u user) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"user\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\ntype customer struct {\n\tname string\n\temail string\n}\n\nfunc (u customer) String() string {\n\treturn fmt.Sprintf(\"{type: \\\"customer\\\", name: %q, email: %q}\", u.name, u.email)\n}\n\n// =============================================================================\n\nfunc main() {\n\tusers := []user{\n\t\t{name: \"Bill\", email: \"bill@ardanlabs.com\"},\n\t\t{name: \"Ale\", email: \"ale@whatever.com\"},\n\t}\n\n\ts1 := stringify(users)\n\n\tfmt.Println(\"users:\", s1)\n\n\t// -------------------------------------------------------------------------\n\n\tcustomers := []customer{\n\t\t{name: \"Google\", email: \"you@google.com\"},\n\t\t{name: \"MSFT\", email: \"you@msft.com\"},\n\t}\n\n\ts2 := stringify(customers)\n\n\tfmt.Println(\"customers:\", s2)\n}\n","Hash":"nCaapl+iPPWYxarnhbYevkUBMf8="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para completar os exercícios. Uma solução possível é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Implemente uma função genérica chamada \u003ccode\u003emarshal\u003c/code\u003e que possa serializar JSON, mas aceita apenas valores que implementem a interface \u003ccode\u003ejson.Marshaler\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic function named marshal that can marshal JSON but only\n// accepts values that implement the json.Marshaler interface.\npackage main\n\n// Add imports.\n\n// Declare the generic function named marshal that can accept only values\n// of type T that implement the json.Marshaler interface.\n\n// Define a type names user with two fields, name and email.\n\n// Implement a method that implements the json.Marshaler interface. Have the\n// method return a value of type user as JSON.\n\nfunc main() {\n\n\t// Construct a value of type user.\n\n\t// Call the generic marshal function.\n\n\t// Display the returned JSON.\n}\n","Hash":"BK7I3Fdqpz/dU8+DLlI+048Lv+o="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic function named marshal that can marshal JSON but only\n// accepts values that implement the json.Marshaler interface.\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// Implement the generic function named marshal that can accept only values\n// of type T that implement the json.Marshaler interface.\nfunc marshal[T json.Marshaler](v T) ([]byte, error) {\n\tdata, err := json.Marshal(v)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\n// =============================================================================\n\n// Define a type names user with two fields, name and email.\ntype user struct {\n\tname string\n\temail string\n}\n\n// Declare a method that implements the json.Marshaler interface. Have the\n// method return a value of type user as JSON.\nfunc (u user) MarshalJSON() ([]byte, error) {\n\tv := fmt.Sprintf(\"{\\\"name\\\": %q, \\\"email\\\": %q}\", u.name, u.email)\n\treturn []byte(v), nil\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Construct a value of type user.\n\tuser := user{\n\t\tname: \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\t// Call the generic marshal function.\n\ts1, err := marshal(user)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\t// Display the returned JSON.\n\tfmt.Println(\"user:\", string(s1))\n}\n","Hash":"ITVn0ZvAKxUUeQbRq9k3sz5Qqc4="}]}]} ,"generics-type-constraints":{"Title":"Tipo Como Restrição(Constraint)","Description":"Este é um novo conceito em Go onde uma restrição pode ser baseada em um conjunto de tipos concretos.","Pages":[{"Title":"Genéricos - Tipo Como Restrição","Content":"\n \u003ch2\u003eGenéricos - Tipo Como Restrição\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este é um novo conceito em Go onde uma restrição pode ser baseada em um conjunto de tipos concretos.\n\n\n Isso só funciona para genéricos.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Genéricos que o guiará através de todos os\n\n\n exemplos nesta seção do Tour.\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Restrição baseada em tipo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2\u003c/b\u003e: Restrição de tipo predefinido \u0026#34;comparable\u0026#34; (comparável)\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3\u003c/b\u003e: Mistura de restrições de tipo e comportamento\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicativo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Funções genéricas criam um novo tipo de restrição que não pode ser resolvida declarando\n\n\n um conjunto de métodos de comportamento.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Add[T ???](v1 T, v2 T) T {\n return v1 \u0026#43; v2\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui está uma função genérica que deseja aceitar dois valores de algum tipo T, somá-los\n\n\n e então retornar a soma para quem chamou. Este é um problema interessante porque o compilador \n\n\n precisa restringir a chamada à função apenas para valores que podem ser usados em uma operação de adição. \n\n\n Atualmente não há um mecanismo para declarar este tipo de restrição.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A decisão foi continuar a usar a interface para declarar a restrição e adicionar algo novo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype addOnly interface {\n string | int | int8 | int16 | int32 | int64 | float64\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode declarar uma interface que define um conjunto de tipos que formam a restrição. Para então\n\n\n aplicar esta interface à função genérica.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Add[T addOnly](v1 T, v2 T) T {\n return v1 \u0026#43; v2\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Agora o compilador pode validar que o conjunto de tipos é compatível com as operações\n\n\n que a função precisa realizar com valores daqueles tipos. Quando a interface está\n\n\n usando os tipos built-in, as interfaces são reutilizáveis entre pacotes. Quando a lista\n\n\n de tipos representa tipos definidos pelo usuário do pacote, você deve lembrar que essas\n\n\n funções genéricas são limitadas aos tipos de pacotes e nada mais.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Interfaces declaradas com um conjunto de tipos não podem ser usadas em uma função polimórfica\n\n\n tradicional. Isso não faria sentido de qualquer maneira, mas é algo que não parece\n\n\n Go no sentido de que esta mudança na interface não é ortogonal.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Uma ideia é ter identificadores pré-declarados para restrições de operações comuns.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc index[T comparable](list []T, find T) int {\n for i, v := range list {\n if v == find {\n return i\n }\n }\n \n return -1\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A restrição comparable é declarada pela linguagem e aplica uma restrição que\n\n\n os tipos devem ser capazes de serem usados em uma declaração de comparação. Neste exemplo,\n\n\n tanto v quanto find são variáveis do tipo T e estão sendo comparadas. Há uma ideia\n\n\n que um pacote na biblioteca padrão poderia fornecer um conjunto comum de restrições também.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Não existem restrições para declarar uma interface que contenha tanto um conjunto de tipos \n\n\n quanto um conjunto de métodos que definem comportamentos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype matcher[T any] interface {\n type person, food\n match(v T) bool\n}\n \nfunc match[T matcher[T]](list []T, find T) int {\n for i, v := range list {\n if v.match(find) {\n return i\n }\n }\n \n return -1\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Uma interface genérica é declarada onde T é o tipo de valor a ser passado para um\n\n\n método chamado match. A interface também restringe seu uso apenas a valores de tipo definido pelo usuário\n\n\n person e food.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando você olha para a função match, não há uma necessidade óbvia de restringir a\n\n\n função apenas aos tipos person e food. Se este for o caso, a função match\n\n\n deveria ser uma função polimórfica tradicional, não uma função genérica. Se houvesse um\n\n\n bom motivo, uma função genérica poderia ser usada para aplicar este tipo de restrição.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Como uma observação à parte, não tenho certeza se essa funcionalidade é necessária ou faz sentido. \n\n\n Isso é algo que a comunidade precisará descobrir com o tempo.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare a constraint not based on behavior but\n// based on the type of data that is acceptable. This type of constrain is\n// important when functions (like Add) need to perform operations (like +)\n// that are not supported by all types.\npackage main\n\nimport \"fmt\"\n\ntype addOnly interface {\n\tstring | int | int8 | int16 | int32 | int64 | float64\n}\n\nfunc Add[T addOnly](v1 T, v2 T) T {\n\treturn v1 + v2\n}\n\nfunc main() {\n\tfmt.Println(Add(10, 20))\n\tfmt.Println(Add(\"A\", \"B\"))\n\tfmt.Println(Add(3.14159, 2.96))\n}\n","Hash":"wBj5w6XDFTJzoTUr4xHATIpa6dU="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use the predeclared type constraint\n// \"comparable\". A type parameter with the comparable constraint accepts as\n// a type argument any comparable type. It permits the use of == and != with\n// values of that type parameter.\npackage main\n\nimport \"fmt\"\n\nfunc index[T comparable](list []T, find T) int {\n\tfor i, v := range list {\n\t\tif v == find {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\ntype person struct {\n\tname string\n\temail string\n}\n\nfunc main() {\n\tdurations := []int{5000, 10, 40}\n\tfindDur := 10\n\n\ti := index(durations, findDur)\n\tfmt.Printf(\"Index: %d for %d\\n\", i, findDur)\n\n\tpeople := []person{\n\t\t{name: \"bill\", email: \"bill@email.com\"},\n\t\t{name: \"jill\", email: \"jill@email.com\"},\n\t\t{name: \"tony\", email: \"tony@email.com\"},\n\t}\n\tfindPerson := person{name: \"tony\", email: \"tony@email.com\"}\n\n\ti = index(people, findPerson)\n\tfmt.Printf(\"Index: %d for %s\\n\", i, findPerson.name)\n}\n","Hash":"H4hYUHtSNdIJpoFBhmwYO6Mwye8="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to mix type and behavior constraints.\npackage main\n\nimport \"fmt\"\n\n// Defining two concrete types that implement a match method.\n\ntype person struct {\n\tname string\n\temail string\n}\n\nfunc (p person) match(v person) bool {\n\treturn p.name == v.name\n}\n\ntype food struct {\n\tname string\n\tcategory string\n}\n\nfunc (f food) match(v food) bool {\n\treturn f.name == v.name\n}\n\n// The matcher interface defines two constraints. First, it constrains the data\n// to what type is acceptable. Second, it constrains the behavior of the data.\n// The match method requires that a value of type T (to be determined later)\n// will be the input of the method.\n\n// Note: The type list inside the interface is not needed for match to work.\n// I'm trying to show how the type list and behavior can be combined.\n\ntype matcher[T any] interface {\n\tperson | food\n\tmatch(v T) bool\n}\n\n// The match function declares that the value of type T must implement the\n// matcher interface and is used for the slice and value arguments to the\n// function.\n\nfunc match[T matcher[T]](list []T, find T) int {\n\tfor i, v := range list {\n\t\tif v.match(find) {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// =============================================================================\n\nfunc main() {\n\tpeople := []person{\n\t\t{name: \"bill\", email: \"bill@email.com\"},\n\t\t{name: \"jill\", email: \"jill@email.com\"},\n\t\t{name: \"tony\", email: \"tony@email.com\"},\n\t}\n\tfindPerson := person{name: \"tony\"}\n\n\ti := match(people, findPerson)\n\tfmt.Printf(\"Match: Idx: %d for %s\\n\", i, findPerson.name)\n\n\tfoods := []food{\n\t\t{name: \"apple\", category: \"fruit\"},\n\t\t{name: \"carrot\", category: \"veg\"},\n\t\t{name: \"chicken\", category: \"meat\"},\n\t}\n\tfindFood := food{name: \"apple\"}\n\n\ti = match(foods, findFood)\n\tfmt.Printf(\"Match: Idx: %d for %s\\n\", i, findFood.name)\n}\n","Hash":"Delq1ICAgtxU892ZFrBJhwnecE8="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Implemente uma função genérica chamada copyfy que é restrita apenas a fazer\n\n\n cópias de slices do tipo string ou int.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic function named copyfy that is constrained to only\n// making copies of slices of type string or int.\npackage main\n\n// Declare an interface named copyer that creates a constraint on\n// string and int.\n\n// Implement a generic function named copyfy that accepts a slice of some\n// type T but constrained on the copyer interface.\n\nfunc main() {\n\n\t// Construct a slice of string with three values.\n\n\t// Call the copyfy function to make a copy of the slice.\n\n\t// Display the slice and the copy.\n\n\t// Construct a slice of int with three values.\n\n\t// Call the copyfy function to make a copy of the slice.\n\n\t// Display the slice and the copy.\n}\n","Hash":"n4/iURoLOmTfj/Lo8hwL/3MmjEU="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic function named copyfy that is constrained to only\n// making copies of slices of type string or int.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n// Declare an interface named copyer that creates a constraint on\n// string and int.\ntype copyer interface {\n\tstring | int\n}\n\n// Implement a generic function named copyfy that accepts a slice of some\n// type T but constrained on the copyer interface.\nfunc copyfy[T copyer](src []T) []T {\n\tdest := make([]T, len(src))\n\n\tcopy(dest, src)\n\n\treturn dest\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Construct a slice of string with three values.\n\tsrc1 := []string{\"Bill\", \"Jill\", \"Joan\"}\n\n\t// Call the copyfy function to make a copy of the slice.\n\tdest1 := copyfy(src1)\n\n\t// Display the slice and the copy.\n\tfmt.Println(\"src string :\", src1)\n\tfmt.Println(\"dest string:\", dest1)\n\n\t// -------------------------------------------------------------------------\n\n\t// Construct a slice of int with three values.\n\tsrc2 := []int{10, 20, 30}\n\n\t// Call the copyfy function to make a copy of the slice.\n\tdest2 := copyfy(src2)\n\n\t// Display the slice and the copy.\n\tfmt.Println(\"src int :\", src2)\n\tfmt.Println(\"dest int:\", dest2)\n}\n","Hash":"4RsnZlqcCtUSyNPLWaXrLEZmX0E="}]}]} ,"context":{"Title":"Pacote Context","Description":"O pacote context define o tipo Context, que transporta prazos, sinais de cancelamento e outros valores com escopo de requisição através dos limites da API e entre processos.","Pages":[{"Title":"Pacote Context","Content":"\n \u003ch2\u003ePacote Context\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O pacote context define o tipo Context, que transporta prazos, sinais de cancelamento e\n\n\n outros valores com escopo de requisição através dos limites da API e entre processos.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \n \u003cp\u003e\n Os valores de context são dados com escopo de requisição que passam por programas\n\n\n em um sistema distribuído.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Armazenar / Recuperar Valores\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e WithCancel\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e WithDeadline\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e WithTimeout\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Request/Response\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e Cancelamento\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eSemântica do Context\u003c/h2\u003e\n \n \n \u003cp\u003e\n A linguagem de programação Go possui a palavra-chave built-in go para criar goroutines,\n\n\n mas não possui palavras-chave ou suporte direto para encerrar goroutines. Em um serviço\n\n\n do mundo real, a capacidade de expirar e encerrar goroutines é crítica para manter\n\n\n a saúdo e operação de um serviço. Nenhuma requisição ou tarefa pode ser executada\n\n\n para sempre, então identificar e gerenciar a latência é uma responsabilidade de todo\n\n\n programador.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A solução fornecida pelo time do Go para resolver esse problema é o pacote Context.\n\n\n Ele foi escrito e apresentado por Sammeer Ajmani em 2014 na conferência Gotham Go.\n\n\n Ele também escreveu uma postagem no Go blog.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Slides: \u003ca href=\"https://talks.golang.org/2014/gotham-context.slide#1\" target=\"_blank\"\u003ehttps://talks.golang.org/2014/gotham-context.slide#1\u003c/a\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Blog Post: \u003ca href=\"https://blog.golang.org/context\" target=\"_blank\"\u003ehttps://blog.golang.org/context\u003c/a\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Através deste trabalho publicado e conversas com Sameer ao longo dos anos,\n\n\n um conjunto de semânticas foi desenvolvido.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eRequisições\u003c/b\u003e \u003cb\u003erecebidas\u003c/b\u003e \u003cb\u003eem\u003c/b\u003e \u003cb\u003eum\u003c/b\u003e \u003cb\u003eservidor\u003c/b\u003e \u003cb\u003edevem\u003c/b\u003e \u003cb\u003ecriar\u003c/b\u003e \u003cb\u003eum\u003c/b\u003e \u003cb\u003eContext\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O momento de criar um Context é sempre o mais cedo possível no processamento de uma\n\n\n requisição ou tarefa. Trabalhar com Context no início de um ciclo de desenvolvimento\n\n\n forçará você a projetar APIs que recebem um Context como primeiro parâmetro. Mesmo\n\n\n que você não esteja 100% certo de que uma função precisa de um Context, é mais fácil\n\n\n remover o Context de algumas funções do que tentar adicionar o Context mais tarde.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e75 // Handle é o nosso mecanismo para montar Handlers para um determinado par de\n76 // verbo e caminho HTTP, o que torna o roteamento realmente fácil e conveniente.\n77 func (a *App) Handle(verb, path string, handler Handler, mw ...Middleware) {\n...\n85 // The function to execute for each request.\n86 h := func(w http.ResponseWriter, r *http.Request, params map[string]string) {\n87 ctx, span := trace.StartSpan(r.Context(), \u0026#34;internal.platform.web\u0026#34;)\n88 defer span.End()\n...\n106 // Add this handler for the specified verb and route.\n107 a.TreeMux.Handle(verb, path, h)\n108 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você vê o código retirado do projeto service que ensinamos no Ardan Labs. A linha 86\n\n\n define uma função handler que está vinculada a todas as rotas como mostrado na linha 107.\n\n\n É essa função que começa a processar quaisquer requisições recebidas. Na linha 87, é\n\n\n criado um span para a requisição que leva como primeiro parâmetro um Context. Esta é\n\n\n a primeira vez que um Context é necessário no código do service.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O que é ótimo aqui é que o valor http.Request já contém um Context. Isso foi adicionado\n\n\n na versão 1.7 do Go. Isso significa que o código não precisa criar manualmente um Context\n\n\n de nível superior. Se estivéssemos usando a versão 1.8 do Go, você precisaria criar\n\n\n um Context vazio antes da chamada para StartSpan usando a função context.Background.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ehttps://golang.org/pkg/context/#Background\n\n87 ctx := context.Background()\n88 ctx, span := trace.StartSpan(ctx, \u0026#34;internal.platform.web\u0026#34;)\n89 defer span.End()\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta é a aparência do código na versão 1.8 do Go. Conforme descrito na documentação \n\n\n do pacote,\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Background retorna um Context vazio e não nil. Ele nunca é cancelado, não tem valores,\n\n\n e não tem prazo. Ele normalmente é usado pela função main, inicialização e testes\n\n\n e como Context de nível superior para requisições recebidas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n É idiomático em Go usar ctx como nome da variável para todos os valores de Context.\n\n\n Como Context é uma interface, nenhuma semântica de ponteiro deve ser usada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ehttps://golang.org/pkg/context/#Context\n\ntype Context interface {\n Deadline() (deadline time.Time, ok bool)\n Done() \u0026lt;-chan struct{}\n Err() error\n Value(key interface{}) interface{}\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Toda função que aceita um Context deve obter sua própria cópia do valor da interface.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eChamadas\u003c/b\u003e \u003cb\u003epara\u003c/b\u003e \u003cb\u003eservidores\u003c/b\u003e \u003cb\u003edevem\u003c/b\u003e \u003cb\u003eaceitar\u003c/b\u003e \u003cb\u003eum\u003c/b\u003e \u003cb\u003eContext\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A ideia por trás dessa semântica é que chamadas de alto nível precisam informar\n\n\n às chamadas de baixo nível quanto tempo estão dispostas a esperar. Um ótimo exemplo\n\n\n disso é o pacote http e as alterações da versão 1.7 feitas no método Do para respeitar\n\n\n os limites de tempo em uma requisição.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e01 package main\n02 \n03 import (\n04 \u0026#34;context\u0026#34;\n05 \u0026#34;io\u0026#34;\n06 \u0026#34;log\u0026#34;\n07 \u0026#34;net/http\u0026#34;\n08 \u0026#34;os\u0026#34;\n09 \u0026#34;time\u0026#34;\n10 )\n11 \n12 func main() {\n13\n14 // Cria um novo request.\n15 req, err := http.NewRequest(\u0026#34;GET\u0026#34;, \u0026#34;https://www.ardanlabs.com/blog/post/index.xml\u0026#34;, nil)\n16 if err != nil {\n17 log.Println(\u0026#34;ERROR:\u0026#34;, err)\n18 return\n19 }\n20\n21 // Cria um context com um tempo limite de 50 milisegundos.\n22 ctx, cancel := context.WithTimeout(req.Context(), 50*time.Millisecond)\n23 defer cancel()\n24\n25 // Vincula o novo context ao request.\n26 req = req.WithContext(ctx)\n27\n28 // Faz a chamada web e retorna qualquer erro. Vai lidar com\n29 // o tempo limite do context.\n30 resp, err := http.DefaultClient.Do(req)\n31 if err != nil {\n32 log.Println(\u0026#34;ERROR:\u0026#34;, err)\n33 return\n34 }\n35\n36 // Chama a função Close no corpo da resposta no retorno.\n37 defer resp.Body.Close()\n38\n39 // Escreve a resposta para o stdout.\n40 io.Copy(os.Stdout, resp.Body)\n41 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este programa emite uma requisição para o feed do blog rss do Ardan com um tempo\n\n\n limite de 50 milissegundos. Nas linhas 15 a 19, a requisição é criada para fazer\n\n\n uma chamada GET para a URL fornecida. As linhas 22-23 criam um Context com um\n\n\n tempo limite de 50 milissegundos. Uma nova API adicionada ao valor Request na\n\n\n versão 1.7 é o método WithContext. Este método permite que o campo Context do\n\n\n valor Request seja atualizado. Na linha 26, isso é exatamente o que o código\n\n\n está fazendo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Na linha 30, a requisição real é feita usando o método Do do pacote http do valor\n\n\n DefaultClient. O método Do respeitará o valor de tempo limite de 50 milissegundos\n\n\n que agora está definido dentro do Context no valor do Request. O que você está vendo\n\n\n é o código (função de alto nível) informando o método Do (função de baixo nível) quanto\n\n\n tempo nós estamos dispostos a esperar a operação Do completar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eNão\u003c/b\u003e \u003cb\u003earmazene\u003c/b\u003e \u003cb\u003eContexts\u003c/b\u003e \u003cb\u003edentro\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003euma\u003c/b\u003e \u003cb\u003estruct\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Em vez disso, passe um Context explicitamente para cada função que precisa dele.\n\n\n Essencialmente, qualquer função que esteja executando I/O deve aceitar um valor de Context\n\n\n como seu primeiro parâmetro e respeitar qualquer tempo limite ou prazo configurado\n\n\n pelo chamador. No caso do Request, havia problemas de compatibilidade com versões anteriores\n\n\n a serem considerados. Então, em vez de alterar as APIs, foi implementada a mecânica\n\n\n mostrada na última seção.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Existem exceções para todas as regras. No entanto, no âmbito deste post e de quaisquer\n\n\n APIs da biblioteca padrão que recebem um Context, o idioma é que o primeiro parâmetro\n\n\n aceite o valor do Context.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/context_figure1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/context_figure1.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n A figura mostra um exemplo do pacote net onde o primeiro parâmetro de cada método\n\n\n recebe um Context como primeiro parâmetro e usa o idioma de nome de variável ctx.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eO\u003c/b\u003e \u003cb\u003eContext\u003c/b\u003e \u003cb\u003edeve\u003c/b\u003e \u003cb\u003eser\u003c/b\u003e \u003cb\u003epropagado\u003c/b\u003e \u003cb\u003epela\u003c/b\u003e \u003cb\u003ecadeia\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003echamadas\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003efunções\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esta é uma regra importante, pois um Context é baseado em uma requisição ou tarefa.\n\n\n Você quer que o Context e quaisquer alterações feitas nele durante o processamento\n\n\n de uma requisição ou tarefa seja propagado e respeitado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e23 // List retorna todos os usuários existentes no sistema.\n24 func (u *User) List(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {\n25 ctx, span := trace.StartSpan(ctx, \u0026#34;handlers.User.List\u0026#34;)\n26 defer span.End()\n27\n28 users, err := user.List(ctx, u.db)\n29 if err != nil {\n30 return err\n31 }\n32\n33 return web.Respond(ctx, w, users, http.StatusOK)\n34 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Nesta listagem você vê uma função handler chamada List que é executada quando\n\n\n um usuário faz uma requisição HTTP para esse endpoint. O handler aceita como\n\n\n primeiro parâmetro um Context, pois faz parte de uma requisição e realizará I/O.\n\n\n Você pode ver nas linhas 25, 28 e 33 que o mesmo valor de Context é propagado\n\n\n pela pilha de chamadas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Um novo valor de Context não é criado, pois esta função não requer alterações nele.\n\n\n Se um novo Context de nível superior fosse criado por esta função, qualquer informação\n\n\n existente no Context de uma chamada de nível superior associada a essa requisição\n\n\n seria perdida. Isso não é o que você quer.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e33 // List retorna uma lista de usuários existentes no banco de dados.\n34 func List(ctx context.Context, db *sqlx.DB) ([]User, error) {\n35 ctx, span := trace.StartSpan(ctx, \u0026#34;internal.user.List\u0026#34;)\n36 defer span.End()\n37\n38 users := []User{}\n39 const q = `SELECT * FROM users`\n40\n41 if err := db.SelectContext(ctx, \u0026amp;users, q); err != nil {\n42 return nil, errors.Wrap(err, \u0026#34;selecting users\u0026#34;)\n43 }\n44\n45 return users, nil\n46 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você vê a declaração do método List que foi chamado na linha 28. Mais uma vez\n\n\n este método aceita um Context como seu primeiro parâmetro. Este valor é então\n\n\n propagado pela pilha de chamdas mais uma vez nas linhas 35 e 41. Como a linha 41\n\n\n é uma chamada de banco de dados, essa função deve respeitar qualquer informação\n\n\n de tempo limite definida no Context do chamador acima.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eSubstitua\u003c/b\u003e \u003cb\u003eum\u003c/b\u003e \u003cb\u003eContext\u003c/b\u003e \u003cb\u003eusando\u003c/b\u003e \u003cb\u003eWithCancel,\u003c/b\u003e \u003cb\u003eWithDeadline,\u003c/b\u003e \u003cb\u003eWithTimeout\u003c/b\u003e \u003cb\u003eou\u003c/b\u003e \u003cb\u003eWithValue\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Porque cada função pode adicionar/modificar o Context para suas necessidades específicas,\n\n\n e essas mudanças não devem afetar nenhuma função que foi chamada antes dela, o Context\n\n\n usa semântica de valor. Isso significa que qualquer alteração em um valor de Context\n\n\n cria um novo valor de Context que é então propagado adiante.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e01 func main() {\n02\n03 // Define uma duração.\n04 duration := 150 * time.Millisecond\n05\n06 // Cria um context que pode ser cancelado manualmente e sinalizará\n07 // o cancelamento na duração especificada.\n08 ctx, cancel := context.WithTimeout(context.Background(), duration)\n09 defer cancel()\n10\n11 // Cria um canal para receber um sinal de que o trabalho foi concluído.\n12 ch := make(chan data, 1)\n13\n14 // Pede para a goroutine fazer algum trabalho para nós.\n15 go func() {\n16\n17 // Simula um trabalho.\n18 time.Sleep(50 * time.Millisecond)\n19\n20 // Informa que o trabalho foi concluído.\n21 ch \u0026lt;- data{\u0026#34;123\u0026#34;}\n22 }()\n23\n24 // Espera o trabalho finalizar. Se demorar muito, segue em frente.\n25 select {\n26 case d := \u0026lt;-ch:\n27 fmt.Println(\u0026#34;work complete\u0026#34;, d)\n28\n29 case \u0026lt;-ctx.Done():\n30 fmt.Println(\u0026#34;work cancelled\u0026#34;)\n31 }\n32 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este é um pequeno programa que mostra a natureza semântica de valor da função\n\n\n WithTimeout. Na linha 08, a chamada para WithTimeout retorna um novo valor de\n\n\n Context e uma função de cancelamento. Como a chamada de função requer um Context\n\n\n pai, o código usa a função Background para criar um Context vazio de nível superior.\n\n\n É para isso que serve a função Background.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Seguindo em frente, o valor Context criado pela função WithTimeout é usado. Se\n\n\n quaisquer funções futuras na cadeia de chamadas precisarem de seu próprio limite\n\n\n de tempo ou prazo específico, elas também devem usar a função With apropriada e\n\n\n este novo valor Context como o pai.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n É extremamente importante que qualquer função de cancelamento retornada de uma\n\n\n função With seja executada antes do retorno da função. É por isso que é idiomático\n\n\n usar a palavra-chave defer logo após a chamada With, como você vê na linha 09.\n\n\n Não fazer isso causará vazamentos de memória em seu programa.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eQuando\u003c/b\u003e \u003cb\u003eum\u003c/b\u003e \u003cb\u003eContext\u003c/b\u003e \u003cb\u003eé\u003c/b\u003e \u003cb\u003ecancelado,\u003c/b\u003e \u003cb\u003etodos\u003c/b\u003e \u003cb\u003eos\u003c/b\u003e \u003cb\u003eContexts\u003c/b\u003e \u003cb\u003ederivados\u003c/b\u003e \u003cb\u003edele\u003c/b\u003e \u003cb\u003esão\u003c/b\u003e \u003cb\u003etambém\u003c/b\u003e \u003cb\u003ecancelados\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O uso da semântica de valor para a API de Context significa que cada novo valor\n\n\n de Context recebe tudo o que o Context pai possui, além de quaisquer novas alterações.\n\n\n Isto significa que se um Context pai é cancelado, todos os filhos derivados desse\n\n\n Context pai são cancelados também.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e01 func main() {\n02\n03 // Cria um Context que pode ser cancelado.\n04 ctx, cancel := context.WithCancel(context.Background())\n05 defer cancel()\n06\n07 // Usa o Waitgroup para orquestração.\n08 var wg sync.WaitGroup\n09 wg.Add(10)\n10\n11 // Cria dez goroutines que derivarão um Context daqule\n12 // criado acima.\n13 for i := 0; i \u0026lt; 10; i\u0026#43;\u0026#43; {\n14 go func(id int) {\n15 defer wg.Done()\n16\n17 // Deriva um novo Context para esta goroutine a partir do\n18 // Context pertencente à função principal.\n19 ctx := context.WithValue(ctx, key, id)\n20\n21 // Espera até o Context ser cancelado.\n22 \u0026lt;-ctx.Done()\n23 fmt.Println(\u0026#34;Cancelled:\u0026#34;, id)\n24 }(i)\n25 }\n26\n27 // Cancela o Context e quaisquer Context\u0026#39;s derivados também.\n28 cancel()\n29 wg.Wait()\n30 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este programa cria um valor de Context que pode ser cancelado na linha 04. Em seguida,\n\n\n nas linhas 13-25, dez goroutines são criadas. Cada goroutine coloca seu próprio\n\n\n id único dentro do seu próprio valor de Context na linha 19. Na chamada para\n\n\n WithValue é passado o valor de Context da função main como seu pai. Então na\n\n\n linha 22, cada goroutine espera até que seu próprio Context seja cancelado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Na linha 28, a goroutine main cancela seu valor de Context e então espera na linha 29\n\n\n todas as dez goroutines receberem o sinal antes de desligar o programa.\n\n\n Uma vez que a função cancel é chamada, todas as dez goroutines na linha 41 vão ficar\n\n\n desbloqueadas e imprimir que foram canceladas. Uma chamada para cancel vai cancelar\n\n\n todas elas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Isso também mostra que o mesmo Context pode ser passado para funções executadas\n\n\n em diferentes goroutines. É seguro usar um Context simultaneamente em várias goroutines.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Não passe um Context nil, mesmo que uma função permita. Passe um TODO context se\n\n\n você não tem certeza sobre qual Context usar. Uma das minhas partes favoritas\n\n\n do pacote Context é a função TODO. Eu acredito firmemente que um programador\n\n\n está sempre rascunhando código. Isso não é diferente de um escritor que está redigindo\n\n\n versões de um artigo. Você nunca sabe tudo enquanto escreve o código, mas espero que\n\n\n saiba o suficiente para levar as coisas adiante. No final, você está constantemente\n\n\n aprendendo, refatorando e testando ao longo do caminho.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Muitas vezes eu sabia que precisava de um Context mas não tinha certeza de onde\n\n\n ele iria vir. Eu sabia que eu não era responsável pela criação do Context de nível\n\n\n superior, portanto, usar a função Background estava fora de questão. Eu precisava\n\n\n de um Context temporário de nível superior até descobrir de onde o Context real\n\n\n viria. Essa é a situação em que você deve usar a função TODO em vez da função Background.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eUse\u003c/b\u003e \u003cb\u003evalores\u003c/b\u003e \u003cb\u003edo\u003c/b\u003e \u003cb\u003eContext\u003c/b\u003e \u003cb\u003esomente\u003c/b\u003e \u003cb\u003epara\u003c/b\u003e \u003cb\u003edados\u003c/b\u003e \u003cb\u003ecom\u003c/b\u003e \u003cb\u003eescopo\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003erequisição\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Não use o Context para passar parâmetros opcionais para funções. Essa pode ser a\n\n\n semântica mais importante de todas. Não use o valor Context para passar dados para\n\n\n uma função quando esses dados são exigidos para executar seu código com sucesso.\n\n\n Em outras palavras, uma função deve ser capaz de executar sua lógica com um Context\n\n\n que não possui valores. Nos casos onde uma função exige que a informação esteja no\n\n\n Context, se essa informação estiver faltando, o programa deverá falhar e sinalizar\n\n\n o encerramento da aplicação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Um exemplo clássico de uso indevido da passagem de dados para uma chamada de função\n\n\n usando Context é com conexões de banco de dados. Como regra geral, você deseja seguir\n\n\n esta ordem quando move dados em seu programa.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Passar os dados como um parâmetro de função. Esta é a maneira mais clara de mover\n\n\n os dados em seu programa sem ocultá-los.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Passar os dados pelo receiver. Se a função que precisa dos dados não puder ter\n\n\n sua assinatura alterada, então use um método e passe os dados pelo receiver.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Exemplo rápido de uso de um receiver\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Handlers de requisição são um exemplo clássico da segunda regra. Como uma função handler\n\n\n está vinculada a uma declaração específica, a assinatura do handler não pode ser alterada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e23 // List retorna todos os usuários existentes no sistema.\n24 func (u *User) List(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {\n25 ctx, span := trace.StartSpan(ctx, \u0026#34;handlers.User.List\u0026#34;)\n26 defer span.End()\n27\n28 users, err := user.List(ctx, u.db)\n29 if err != nil {\n30 return err\n31 }\n32\n33 return web.Respond(ctx, w, users, http.StatusOK)\n34 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui você vê o método handler List do projeto service. A assinatura desses\n\n\n métodos está vinculada ao que o framework web definiu e não pode ser alterada.\n\n\n Porém, para realizar a chamada de negócio na linha 28, uma conexão com banco de\n\n\n dados é necessária. Esse código localiza o pool de conexões não no valor do Context\n\n\n passado, mas no receiver.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e15 // User representa o conjunto de handlers da API User.\n16 type User struct {\n17 db *sqlx.DB\n18 authenticator *auth.Authenticator\n19\n20 // ADICIONE OUTRO ESTADO COMO LOGGER E CONFIG AQUI.\n21 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você vê a declaração do tipo de receiver. Qualquer coisa que um handler de requisições\n\n\n precisa é definido como campos. Isso permite que as informações não fiquem ocultas\n\n\n e que a camada de negócios funcione com um valor de Context vazio.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e14 // API constrói um http.Handler com todas as rotas da aplicação definidas.\n15 func API(shutdown chan os.Signal, log *log.Logger, db *sqlx.DB, authenticator *auth.Authenticator) http.Handler {\n16\n...\n26 // Registra endpoints de gerenciamento e autenticação de usuários.\n27 u := User{\n28 db: db,\n29 authenticator: authenticator,\n30 }\n31\n32 app.Handle(\u0026#34;GET\u0026#34;, \u0026#34;/v1/users\u0026#34;, u.List)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este código constrói um valor User e, em seguida, vincula o método List à rota.\n\n\n Mais uma vez, como a assinatura de uma função handler é imutável, usar um receiver\n\n\n e métodos é a próxima melhor maneira de passar dados sem que eles fiquem ocultos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eDados\u003c/b\u003e \u003cb\u003epara\u003c/b\u003e \u003cb\u003edebug\u003c/b\u003e \u003cb\u003eou\u003c/b\u003e \u003cb\u003etracing\u003c/b\u003e \u003cb\u003esão\u003c/b\u003e \u003cb\u003eseguros\u003c/b\u003e \u003cb\u003epara\u003c/b\u003e \u003cb\u003eserem\u003c/b\u003e \u003cb\u003epassados\u003c/b\u003e \u003cb\u003eem\u003c/b\u003e \u003cb\u003eum\u003c/b\u003e \u003cb\u003eContext\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Os dados que podem ser armazenados e recebidos de um valor de Context são informações de\n\n\n debug e tracing.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e23 // Values representa estado para cada requisição.\n24 type Values struct {\n25 TraceID string\n26 Now time.Time\n27 StatusCode int\n28 }\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui está uma declaração de um tipo que é construído e armazenado dentro de cada\n\n\n valor de Context criado para uma nova requisição. Os três campos fornecem tracing\n\n\n e informações de debug para a requisição. Essas informações são coletadas à medida\n\n\n que a solicitação avança.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e75 // Handle é nosso mecanismo para montar Handlers para um dado par de verbo e\n76 // caminho HTTP, isso torna o roteamento realmente fácil e conveniente.\n77 func (a *App) Handle(verb, path string, handler Handler, mw ...Middleware) {\n78\n...\n79 // A função a ser executada para cada solicitação.\n80 h := func(w http.ResponseWriter, r *http.Request, params map[string]string) {\n…\n84 // Define o context com os valores necessários para\n85 // processar a requisição.\n86 v := Values{\n87 TraceID: span.SpanContext().TraceID.String(),\n88 Now: time.Now(),\n89 }\n90 ctx = context.WithValue(ctx, KeyValues, \u0026amp;v)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Veja como o tipo Values é construído na linha 86 e então armazenado dentro do Context\n\n\n na linha 90. É o middleware de logging que precisa da maior parte dessas informações.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e20 // Cria um handler que será anexado na cadeia de middleware.\n21 h := func(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {\n...\n25 // Se o context não possuir esse valor, solicite que o serviço\n26 // seja encerrado de forma graciosa.\n27 v, ok := ctx.Value(web.KeyValues).(*web.Values)\n28 if !ok {\n29 return web.NewShutdownError(\u0026#34;web value missing from context\u0026#34;)\n30 }\n...\n34 log.Printf(\u0026#34;%s : (%d) : %s %s -\u0026gt; %s (%s)\u0026#34;,\n35 v.TraceID, v.StatusCode,\n36 r.Method, r.URL.Path,\n37 r.RemoteAddr, time.Since(v.Now),\n38 )\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A consequência de passar informações através do Context é mostrada no código nas\n\n\n linhas 27-30. O código está tentando recuperar os dados de Values do Context\n\n\n e verificando se os dados estão lá. Se os dados não estiverem lá, então um grande\n\n\n problema de integridade existe e o serviço precisa ser encerrado. Isso é feito no\n\n\n código do service enviando de volta um valor de erro especial por meio da aplicação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se você estiver passando conexões de banco de dados ou informações de usuário para\n\n\n sua camada de negócios usando um Context, você tem dois problemas:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVocê precisa verificar a integridade e precisa de um mecanismo para encerrar o serviço rapidamente.\u003c/li\u003e\n \n \u003cli\u003eTestar e debugar torna-se muito mais difícil e complicado. Você está abandonando uma melhor clareza e legibilidade em seu código.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eRequisições recebidas em um servidor devem criar um Context.\u003c/li\u003e\n \n \u003cli\u003eChamadas para servidores devem aceitar um Context.\u003c/li\u003e\n \n \u003cli\u003eO Context deve ser propagado pela cadeia de chamadas de funções.\u003c/li\u003e\n \n \u003cli\u003eSubstitua um Context usando WithCancel, WithDeadline, WithTimeout, ou WithValue.\u003c/li\u003e\n \n \u003cli\u003eQuando um Context é cancelado, todos os Contexts derivados também são cancelados.\u003c/li\u003e\n \n \u003cli\u003eNão armazene Contexts dentro de uma struct; em vez disso, passe o Context explicitamente para cada função que precisa dele.\u003c/li\u003e\n \n \u003cli\u003eNão passe um Context nil, mesmo que uma função permita isso. Passe context.TODO se você não tem certeza sobre qual Context usar.\u003c/li\u003e\n \n \u003cli\u003eUse os valores do Context apenas para dados com escopo de requisição que transitam por processos e APIs, e não para passar parâmetros opcionais para funções.\u003c/li\u003e\n \n \u003cli\u003eO mesmo Context pode ser passado para funções executando em goroutines diferentes; Contexts são seguros para uso simultâneo por várias goroutines.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2019/09/context-package-semantics-in-go.html\" target=\"_blank\"\u003eContext Package Semantics In Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/pkg/context\" target=\"_blank\"\u003ePacote context\u003c/a\u003e - Go Team \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/context\" target=\"_blank\"\u003eGo Concurrency Patterns: Context\u003c/a\u003e - Sameer Ajmani \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://rakyll.org/leakingctx/\" target=\"_blank\"\u003eUsing contexts to avoid leaking goroutines\u003c/a\u003e - JBD \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to store and retrieve\n// values from a context.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\n// TraceID is represents the trace id.\ntype TraceID string\n\n// TraceIDKey is the type of value to use for the key. The key is\n// type specific and only values of the same type will match.\ntype TraceIDKey int\n\nfunc main() {\n\n\t// Create a traceID for this request.\n\ttraceID := TraceID(\"f47ac10b-58cc-0372-8567-0e02b2c3d479\")\n\n\t// Declare a key with the value of zero of type userKey.\n\tconst traceIDKey TraceIDKey = 0\n\n\t// Store the traceID value inside the context with a value of\n\t// zero for the key type.\n\tctx := context.WithValue(context.Background(), traceIDKey, traceID)\n\n\t// Retrieve that traceID value from the Context value bag.\n\tif uuid, ok := ctx.Value(traceIDKey).(TraceID); ok {\n\t\tfmt.Println(\"TraceID:\", uuid)\n\t}\n\n\t// Retrieve that traceID value from the Context value bag not\n\t// using the proper key type.\n\tif _, ok := ctx.Value(0).(TraceID); !ok {\n\t\tfmt.Println(\"TraceID Not Found\")\n\t}\n}\n","Hash":"naTovoYRG4UWvm8qL/T9CksMl3Q="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use the WithCancel function.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\n\t// Create a context that is cancellable only manually.\n\t// The cancel function must be called regardless of the outcome.\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\t// Ask the goroutine to do some work for us.\n\tgo func() {\n\n\t\t// Wait for the work to finish. If it takes too long move on.\n\t\tselect {\n\t\tcase \u003c-time.After(100 * time.Millisecond):\n\t\t\tfmt.Println(\"moving on\")\n\n\t\tcase \u003c-ctx.Done():\n\t\t\tfmt.Println(\"work complete\")\n\t\t}\n\t}()\n\n\t// Simulate work.\n\ttime.Sleep(50 * time.Millisecond)\n\n\t// Report the work is done.\n\tcancel()\n\n\t// Just hold the program to see the output.\n\ttime.Sleep(time.Second)\n}\n","Hash":"xq0j0EPwtvc8EwRYsn4mOafgVS8="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use the WithDeadline function.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n)\n\ntype data struct {\n\tUserID string\n}\n\nfunc main() {\n\n\t// Set a deadline.\n\tdeadline := time.Now().Add(150 * time.Millisecond)\n\n\t// Create a context that is both manually cancellable and will signal\n\t// a cancel at the specified date/time.\n\tctx, cancel := context.WithDeadline(context.Background(), deadline)\n\tdefer cancel()\n\n\t// Create a channel to received a signal that work is done.\n\tch := make(chan data, 1)\n\n\t// Ask the goroutine to do some work for us.\n\tgo func() {\n\n\t\t// Simulate work.\n\t\ttime.Sleep(200 * time.Millisecond)\n\n\t\t// Report the work is done.\n\t\tch \u003c- data{\"123\"}\n\t}()\n\n\t// Wait for the work to finish. If it takes too long move on.\n\tselect {\n\tcase d := \u003c-ch:\n\t\tfmt.Println(\"work complete\", d)\n\n\tcase \u003c-ctx.Done():\n\t\tfmt.Println(\"work cancelled\")\n\t}\n}\n","Hash":"FC9EpJsdBquD4gDdwT3fNeMBhP8="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use the WithTimeout function\n// of the Context package.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n)\n\ntype data struct {\n\tUserID string\n}\n\nfunc main() {\n\n\t// Set a duration.\n\tduration := 150 * time.Millisecond\n\n\t// Create a context that is both manually cancellable and will signal\n\t// a cancel at the specified duration.\n\tctx, cancel := context.WithTimeout(context.Background(), duration)\n\tdefer cancel()\n\n\t// Create a channel to received a signal that work is done.\n\tch := make(chan data, 1)\n\n\t// Ask the goroutine to do some work for us.\n\tgo func() {\n\n\t\t// Simulate work.\n\t\ttime.Sleep(50 * time.Millisecond)\n\n\t\t// Report the work is done.\n\t\tch \u003c- data{\"123\"}\n\t}()\n\n\t// Wait for the work to finish. If it takes too long move on.\n\tselect {\n\tcase d := \u003c-ch:\n\t\tfmt.Println(\"work complete\", d)\n\n\tcase \u003c-ctx.Done():\n\t\tfmt.Println(\"work cancelled\")\n\t}\n}\n","Hash":"PNJK9G0olMrw95FUwcrb0t9i42g="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program that implements a web request with a context that is\n// used to timeout the request if it takes too long.\npackage main\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n)\n\nfunc main() {\n\n\t// Create a new request.\n\treq, err := http.NewRequest(\"GET\", \"https://www.ardanlabs.com/blog/post/index.xml\", nil)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn\n\t}\n\n\t// Create a context with a timeout of 50 milliseconds.\n\tctx, cancel := context.WithTimeout(req.Context(), 50*time.Millisecond)\n\tdefer cancel()\n\n\t// Bind the new context into the request.\n\treq = req.WithContext(ctx)\n\n\t// Make the web call and return any error. Do will handle the\n\t// context level timeout.\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn\n\t}\n\n\t// Close the response body on the return.\n\tdefer resp.Body.Close()\n\n\t// Write the response to stdout.\n\tio.Copy(os.Stdout, resp.Body)\n}\n","Hash":"2ckcQd/UNVOnJ7Ryir0OTJCdP7w="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show when a Context is canceled, all Contexts\n// derived from it are also canceled.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n)\n\n// Need a key type.\ntype myKey int\n\n// Need a key value.\nconst key myKey = 0\n\nfunc main() {\n\n\t// Create a Context that can be cancelled.\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\t// Use the Waitgroup for orchestration.\n\tvar wg sync.WaitGroup\n\twg.Add(10)\n\n\t// Create ten goroutines that will derive a Context from\n\t// the one created above.\n\tfor i := 0; i \u003c 10; i++ {\n\t\tgo func(id int) {\n\t\t\tdefer wg.Done()\n\n\t\t\t// Derive a new Context for this goroutine from the Context\n\t\t\t// owned by the main function.\n\t\t\tctx := context.WithValue(ctx, key, id)\n\n\t\t\t// Wait until the Context is cancelled.\n\t\t\t\u003c-ctx.Done()\n\t\t\tfmt.Println(\"Cancelled:\", id)\n\t\t}(i)\n\t}\n\n\t// Cancel the Context and any derived Context's as well.\n\tcancel()\n\twg.Wait()\n}\n","Hash":"wN20MYujGaIgc19TayUFcOgXurQ="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo e siga as instruções. Você escreverá um handler web que executa uma chamada de banco de dados simulada, mas atingirá o tempo limite com base em um context se a chamada demorar muito. Você também salvará o estado no context.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Use the template and follow the directions. You will be writing a web handler\n// that performs a mock database call but will timeout based on a context if the call\n// takes too long. You will also save state into the context.\npackage main\n\n// Add imports.\n\n// Declare a new type named `key` that is based on an int.\n\n// Declare a constant named `userIPKey` of type `key` set to\n// the value of 0.\n\n// Declare a struct type named `User` with two `string` based\n// fields named `Name` and `Email`.\n\nfunc main() {\n\troutes()\n\n\tlog.Println(\"listener : Started : Listening on: http://localhost:4000\")\n\thttp.ListenAndServe(\":4000\", nil)\n}\n\n// routes sets the routes for the web service.\nfunc routes() {\n\thttp.HandleFunc(\"/user\", findUser)\n}\n\n// Implement the findUser function to leverage the context for\n// both timeouts and state.\nfunc findUser(rw http.ResponseWriter, r *http.Request) {\n\n\t// Create a context that timeouts in fifty milliseconds.\n\n\t// Defer the call to cancel.\n\n\t// Save the `r.RemoteAddr` value in the context using `userIPKey`\n\t// as the key. This call returns a new context so replace the\n\t// current `ctx` value with this new one. The original context is\n\t// the parent context for this new child context.\n\n\t// Create a channel with a buffer size of 1 that works with\n\t// pointers of type `User` \n\n\t// Use this goroutine to make the database call. Use the channel\n\t// to get the user back.\n\tgo func() {\n\n\t\t// Get the `r.RemoteAddr` value from the context and log\n\t\t// the value you get back.\n\n\t\t// Call the `readDatabase` function provided below and\n\t\t// send the returned `User` pointer on the channel.\n\n\t\t// Log that the goroutine is terminating.\n\t}()\n\n\t// Wait for the database call to finish or the timeout.\n\tselect {\n\n\t// Add a case to wait on the channel for the `User` pointer.\n\n\t\t// Call the `sendResponse` function provided below to\n\t\t// send the `User` to the caller. Use `http.StatusOK`\n\t\t// as the status code.\n\n\t\t// Log we sent the response with a StatusOk\n\t\t\n\t\treturn\n\n\t// Add a case to wait on the `ctx.Done()` channel.\n\n\t\t// Use this struct value for the error response.\n\t\te := struct{ Error string }{ctx.Err().Error()}\n\n\t\t// Call the `sendResponse` function provided below to\n\t\t// send the error to the caller. Use `http.StatusRequestTimeout`\n\t\t// as the status code.\n\n\t\t// Log we sent the response with a StatusRequestTimeout\n\n\t\treturn\n\t}\n}\n\n// readDatabase performs a pretend database call with\n// a second of latency.\nfunc readDatabase() *User {\n\tu := User{\n\t\tName: \"Bill\",\n\t\tEmail: \"bill@ardanlabs.com\",\n\t}\n\n\t// Create 100 milliseconds of latency.\n\ttime.Sleep(100 * time.Millisecond)\n\n\treturn \u0026u\n}\n\n// sendResponse marshals the provided value into json and returns\n// that back to the caller.\nfunc sendResponse(rw http.ResponseWriter, v interface{}, statusCode int) {\n\trw.Header().Set(\"Content-Type\", \"application/json\")\n\trw.WriteHeader(statusCode)\n\tjson.NewEncoder(rw).Encode(v)\n}\n","Hash":"HZiITadZQjvWN3RiPE+b3VhCrlk="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program that implements a simple web service using the\n// context to handle timeouts and pass context into the request.\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n)\n\n// The key type is unexported to prevent collisions with context keys defined in\n// other packages.\ntype key int\n\n// userIPkey is the context key for the user IP address. Its value of zero is\n// arbitrary. If this package defined other context keys, they would have\n// different integer values.\nconst userIPKey key = 0\n\n// User defines a user in the system.\ntype User struct {\n\tName string\n\tEmail string\n}\n\nfunc main() {\n\troutes()\n\n\tlog.Println(\"listener : Started : Listening on: http://localhost:4000\")\n\thttp.ListenAndServe(\":4000\", nil)\n}\n\n// routes sets the routes for the web service.\nfunc routes() {\n\thttp.HandleFunc(\"/user\", findUser)\n}\n\n// findUser makes a database call to find a user.\nfunc findUser(rw http.ResponseWriter, r *http.Request) {\n\n\t// Create a context that timeouts in fifty milliseconds.\n\tctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)\n\tdefer cancel()\n\n\t// Save the user ip address in the context. This call returns\n\t// a new context we now need to use. The original context is\n\t// the parent context for this new child context.\n\tctx = context.WithValue(ctx, userIPKey, r.RemoteAddr)\n\n\t// Create a goroutine to make the database call. Use the channel\n\t// to get the user back.\n\tch := make(chan *User, 1)\n\tgo func() {\n\n\t\t// Get the ip address from the context for logging.\n\t\tif ip, ok := ctx.Value(userIPKey).(string); ok {\n\t\t\tlog.Println(\"Start DB for IP\", ip)\n\t\t}\n\n\t\t// Make the database call and return the value\n\t\t// back on the channel.\n\t\tch \u003c- readDatabase()\n\t\tlog.Println(\"DB goroutine terminated\")\n\t}()\n\n\t// Wait for the database call to finish or the timeout.\n\tselect {\n\tcase u := \u003c-ch:\n\n\t\t// Respond with the user.\n\t\tsendResponse(rw, u, http.StatusOK)\n\t\tlog.Println(\"Sent StatusOK\")\n\t\treturn\n\n\tcase \u003c-ctx.Done():\n\n\t\t// If you have the ability to cancel the database\n\t\t// operation the goroutine is performing do that now.\n\t\t// In this example we can't.\n\n\t\t// Respond with the error.\n\t\te := struct{ Error string }{ctx.Err().Error()}\n\t\tsendResponse(rw, e, http.StatusRequestTimeout)\n\t\tlog.Println(\"Sent StatusRequestTimeout\")\n\t\treturn\n\t}\n}\n\n// readDatabase performs a pretend database call with\n// a second of latency.\nfunc readDatabase() *User {\n\tu := User{\n\t\tName: \"Bill\",\n\t\tEmail: \"bill@ardanlabs.com\",\n\t}\n\n\t// Create 100 milliseconds of latency.\n\ttime.Sleep(100 * time.Millisecond)\n\n\treturn \u0026u\n}\n\n// sendResponse marshals the provided value into json and returns\n// that back to the caller.\nfunc sendResponse(rw http.ResponseWriter, v interface{}, statusCode int) {\n\trw.Header().Set(\"Content-Type\", \"application/json\")\n\trw.WriteHeader(statusCode)\n\tjson.NewEncoder(rw).Encode(v)\n}\n","Hash":"PAg9pG41wNobXGcZnApaSiJ2GbE="}]}]} ,"exporting":{"Title":"Identificadores Exportados","Description":"Exportação fornece a capacidade de declarar se um identificador é acessível ao código fora do pacote em que foi declarado.","Pages":[{"Title":"Identificadores Exportados","Content":"\n \u003ch2\u003eIdentificadores Exportados\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de assistência financeira, use nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudo\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Exportar fornece a capacidade de declarar se um identificador é acessível ao código\n\n\n fora do pacote em que está declarado.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declarar e acessar identificadores exportados\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Declarar identificadores e restrições não exportados\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Acessar valores de identificadores não exportados\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Campos do tipo struct não exportados\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Tipos embedded não exportados\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eFuncionamento da Exportação\u003c/h2\u003e\n \n \n \u003cp\u003e\n Um pacote é a unidade básica do código compilado em Go. \n\n\n Ele representa uma unidade física de código compilado, geralmente como uma biblioteca compilada no sistema operacional hospedeiro. \n\n\n A exportação determina o acesso aos identificadores através dos limites do package.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage counters\n\ntype AlertCounter int\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste caso, a letra maiúscula está sendo usada para nomear o tipo AlterCounter, \n\n\n o tipo é exportado e pode ser referenciado diretamente por código fora do pacote counters.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage counters\n\ntype alertCounter int\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Agora que você alterou o nome do tipo para começar com uma letra minúscula, o tipo não foi exportado. \n\n\n Isso significa que apenas o código dentro do pacote counters pode fazer referência direta a esse tipo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage counters\n\ntype alertCounter int\n\nfunc New(value int) alertCounter {\n return alertCounter(value)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Mesmo que o código acima possua a sintaxe correta e seja compilado, não há valor nele. \n\n\n Retornar um valor de um tipo não exportado é confuso, pois quem chama \n\n\n (que provavelmente existirá em um pacote diferente) não pode fazer referência direta ao nome do tipo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage main\n\nimport (\n \u0026#34;fmt\u0026#34;\n\n \u0026#34;github.com/ardanlabs/.../exporting/example3/counters\u0026#34;\n)\n\nfunc main() {\n counter := counters.New(10)\n fmt.Printf(\u0026#34;Counter: %d\\n\u0026#34;, counter)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste caso, a função main no pacote main chama a função counters.New com sucesso \n\n\n e o compilador pode declarar e construir uma variável do tipo não exportado. Isso não \n\n\n significa que você deva fazer isso nem significa que você está recebendo alguma proteção real para isso. \n\n\n Isso deve ser evitado e, se New retornar um valor, ele deverá ser do tipo exportado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage users\n\ntype User struct {\n Name string\n ID int\n\n password string\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando se trata de campos em uma struct, a primeira letra declara se o campo é\n\n\n acessível ao código fora do pacote em que está declarado. Nesse caso, Name e ID estão acessíveis, \n\n\n mas password não. É idiomático separar campos exportados e não \n\n\n exportados dessa maneira, se isso for razoável ou prático. Normalmente todos os \n\n\n campos seriam um ou outro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage users\n\ntype user struct {\n Name string\n ID int\n}\n\ntype Manager struct {\n Title string\n user\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste cenário, mesmo que o tipo user não seja exportado, ele possui dois campos\n\n\n exportados. Isso significa que quando o tipo user é incorporado ao tipo Manager, exportado, \n\n\n os campos do user são promovidos e estão acessíveis. É comum ter tipos que não são \n\n\n exportados com campos exportados porque o pacote reflection só pode \n\n\n operar em campos exportados. Os Marshallers não funcionarão de outra maneira.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O exemplo cria uma situação ruim onde o código fora do pacote user pode construir \n\n\n um Manager, mas como o tipo user incorporado não é exportado, os campos para \n\n\n esse tipo podem ser inicializados. Isso cria problemas de construção parcial\n\n\n que levarão a bugs. Você precisa ser consistente ao exportar ou não exportar.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eO código em go é compilado em pacotes e depois vinculados.\u003c/li\u003e\n \n \u003cli\u003eOs identificadores são exportados (ou permanecem não exportados) com base em letras maiúsculas e minúsculas.\u003c/li\u003e\n \n \u003cli\u003eImportamos pacotes para acessar identificadores exportados.\u003c/li\u003e\n \n \u003cli\u003eQualquer pacote pode usar um valor de tipo não exportado, mas isso é chato de usar.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003ca href=\"https://www.ardanlabs.com/blog/2014/03/exportedunexported-identifiers-in-go.html\" target=\"_blank\"\u003eExported/Unexported Identifiers In Go\u003c/a\u003e - William Kennedy\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to access an exported identifier.\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"play.ground/counters\"\n)\n\nfunc main() {\n\n\t// Create a variable of the exported type and initialize the value to 10.\n\tcounter := counters.AlertCounter(10)\n\n\tfmt.Printf(\"Counter: %d\\n\", counter)\n}\n\n// -----------------------------------------------------------------------------\n-- counters/counters.go --\n\n// Package counters provides alert counter support.\npackage counters\n\n// AlertCounter is an exported named type that\n// contains an integer counter for alerts.\ntype AlertCounter int\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n\nreplace \"play.ground/counters\" =\u003e ./counters\n","Hash":"3qzY8hyVJoSzio8hdoyPyqwTdmg="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to access an exported identifier.\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"play.ground/counters\"\n)\n\nfunc main() {\n\n\t// Create a variable of the exported type and initialize the value to 10.\n\tcounter := counters.alertCounter(10)\n\n\t// ./example2.go:16: undefined: counters.alertCounter\n\n\tfmt.Printf(\"Counter: %d\\n\", counter)\n}\n\n// -----------------------------------------------------------------------------\n-- counters/counters.go --\n\n// Package counters provides alert counter support.\npackage counters\n\n// alertCounter is an unexported named type that\n// contains an integer counter for alerts.\ntype alertCounter int\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n","Hash":"JmOngEFNogvwW82C8TIpQEreG44="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how the program can access a value\n// of an unexported identifier from another package.\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"play.ground/counters\"\n)\n\nfunc main() {\n\n\t// Create a variable of the unexported type using the exported\n\t// New function from the package counters.\n\tcounter := counters.New(10)\n\n\tfmt.Printf(\"Counter: %d\\n\", counter)\n}\n\n// -----------------------------------------------------------------------------\n-- counters/counters.go --\n\n// Package counters provides alert counter support.\npackage counters\n\n// alertCounter is an unexported named type that\n// contains an integer counter for alerts.\ntype alertCounter int\n\n// New creates and returns values of the unexported type alertCounter.\nfunc New(value int) alertCounter {\n\treturn alertCounter(value)\n}\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n","Hash":"1S8gdbs0iz+Gka/kXoU2M5je3go="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how unexported fields from an exported struct\n// type can't be accessed directly.\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"play.ground/users\"\n)\n\nfunc main() {\n\n\t// Create a value of type User from the users package.\n\tu := users.User{\n\t\tName: \"Chole\",\n\t\tID: 10,\n\n\t\tpassword: \"xxxx\",\n\t}\n\n\t// ./example4.go:21: unknown field password in struct literal of type users.User\n\n\tfmt.Printf(\"User: %#v\\n\", u)\n}\n\n// -----------------------------------------------------------------------------\n-- users/users.go --\n\n// Package users provides support for user management.\npackage users\n\n// User represents information about a user.\ntype User struct {\n\tName string\n\tID int\n\n\tpassword string\n}\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n","Hash":"GcKXz1laqW0DP/p4WHQAWzdV+G8="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to create values from exported types with\n// embedded unexported types.\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"play.ground/users\"\n)\n\nfunc main() {\n\n\t// Create a value of type Manager from the users package.\n\tu := users.Manager{\n\t\tTitle: \"Dev Manager\",\n\t}\n\n\t// Set the exported fields from the unexported user inner type.\n\tu.Name = \"Chole\"\n\tu.ID = 10\n\n\tfmt.Printf(\"User: %#v\\n\", u)\n}\n\n// -----------------------------------------------------------------------------\n-- users/users.go --\n\n// Package users provides support for user management.\npackage users\n\n// User represents information about a user.\ntype user struct {\n\tName string\n\tID int\n}\n\n// Manager represents information about a manager.\ntype Manager struct {\n\tTitle string\n\n\tuser\n}\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n","Hash":"heIqHBMpsUD+PTdd7CyTI34s3R4="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para concluir os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Crie um pacote chamado toy com uma única struct exportada chamado Toy.\n\n\n Adicione os campos exportados Name e Weight. Em seguida, adicione dois campos não exportados chamados onHand\n\n\n e sold. Declare uma \u0026#34;factory function\u0026#34; chamada New para criar valores do tipo toy e aceitar\n\n\n parâmetros para os campos exportados. Em seguida, declare métodos que retornem e atualizem valores\n\n\n para os campos não exportados.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Crie um programa que importe o pacote toy. Use a função New para\n\n\n criar um valor do tipo Toy. Em seguida, use os métodos para definir o acumulador e exibir o\n\n\n valores do campo desse valor de toy.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create a package named toy with a single exported struct type named Toy. Add\n// the exported fields Name and Weight. Then add two unexported fields named\n// onHand and sold. Declare a factory function called New to create values of\n// type toy and accept parameters for the exported fields. Then declare methods\n// that return and update values for the unexported fields.\n//\n// Create a program that imports the toy package. Use the New function to create a\n// value of type toy. Then use the methods to set the counts and display the\n// field values of that toy value.\npackage main\n\nimport (\n\t\"play.ground/toy\"\n)\n\nfunc main() {\n\n\t// Use the New function from the toy package to create a value of\n\t// type toy.\n\n\t// Use the methods from the toy value to set some initialize\n\t// values.\n\n\t// Display each field separately from the toy value.\n}\n\n// -----------------------------------------------------------------------------\n-- toy/toy.go --\n\n// Package toy contains support for managing toy inventory.\npackage toy\n\n// Declare a struct type named Toy with four fields. Name string,\n// Weight int, onHand int and sold int.\n\n// Declare a function named New that accepts values for the\n// exported fields. Return a pointer of type Toy that is initialized\n// with the parameters.\n\n// Declare a method named OnHand with a pointer receiver that\n// returns the current on hand count.\n\n// Declare a method named UpdateOnHand with a pointer receiver that\n// updates and returns the current on hand count.\n\n// Declare a method named Sold with a pointer receiver that\n// returns the current sold count.\n\n// Declare a method named UpdateSold with a pointer receiver that\n// updates and returns the current sold count.\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n","Hash":"XVQEvrhbML2PflX2VG4jZyPf5to="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create a package named toy with a single exported struct type named Toy. Add\n// the exported fields Name and Weight. Then add two unexported fields named\n// onHand and sold. Declare a factory function called New to create values of\n// type toy and accept parameters for the exported fields. Then declare methods\n// that return and update values for the unexported fields.\n//\n// Create a program that imports the toy package. Use the New function to create a\n// value of type toy. Then use the methods to set the counts and display the\n// field values of that toy value.\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"play.ground/toy\"\n)\n\nfunc main() {\n\n\t// Create a value of type toy.\n\tt := toy.New(\"Bat\", 28)\n\n\t// Update the counts.\n\tt.UpdateOnHand(100)\n\tt.UpdateSold(2)\n\n\t// Display each field separately.\n\tfmt.Println(\"Name\", t.Name)\n\tfmt.Println(\"Weight\", t.Weight)\n\tfmt.Println(\"OnHand\", t.OnHand())\n\tfmt.Println(\"Sold\", t.Sold())\n}\n\n// -----------------------------------------------------------------------------\n-- toy/toy.go --\n\n// Package toy contains support for managing toy inventory.\npackage toy\n\n// Toy represents a toy we sell.\ntype Toy struct {\n\tName string\n\tWeight int\n\n\tonHand int\n\tsold int\n}\n\n// New creates values of type toy.\nfunc New(name string, weight int) *Toy {\n\treturn \u0026Toy{\n\t\tName: name,\n\t\tWeight: weight,\n\t}\n}\n\n// OnHand returns the current number of this\n// toy on hand.\nfunc (t *Toy) OnHand() int {\n\treturn t.onHand\n}\n\n// UpdateOnHand updates the on hand count and\n// returns the current value.\nfunc (t *Toy) UpdateOnHand(count int) int {\n\tt.onHand += count\n\treturn t.onHand\n}\n\n// Sold returns the current number of this\n// toy sold.\nfunc (t *Toy) Sold() int {\n\treturn t.sold\n}\n\n// UpdateSold updates the sold count and\n// returns the current value.\nfunc (t *Toy) UpdateSold(count int) int {\n\tt.sold += count\n\treturn t.sold\n}\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n","Hash":"8qY7eR8WSuIVNoNhD8c8M8u4iaE="}]}]} ,"generics-struct-types":{"Title":"Tipo Struct","Description":"Você pode declarar um tipo genérico usando um tipo struct.","Pages":[{"Title":"Generics - Struct Tipo","Content":"\n \u003ch2\u003eGenerics - Struct Tipo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Você pode declarar um tipo genérico usando um tipo struct.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Generics, que mostra todos os\n\n\n exemplos nesta seção do Tour.\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Lista Encadeada, ou Lista Ligada\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicado\u003c/h2\u003e\n \n \n \u003cp\u003e\n E se você quisesse declarar seu próprio tipo genérico usando um tipo struct?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype node[T any] struct {\n Data T\n next *node[T]\n prev *node[T]\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este tipo struct é declarado para representar um node da lista encadeada. Cada nó\n\n\n contém um dado individual que é armazenado e gerenciado pela lista. O uso\n\n\n de colchetes declara que o tipo T é um tipo genérico a ser determinado em\n\n\n tempo de compilação. O uso da restrição \u0026#34;any\u0026#34; descreve que não há restrição\n\n\n que tipo T pode se tornar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Com o tipo T declarado, o campo Data agora pode ser definido como um campo de algum tipo T para\n\n\n ser determinado posteriormente. Os campos next e prev precisam apontar para um node do mesmo\n\n\n tipo T. Estes são os ponteiros para o node seguinte e anterior na lista ligada,\n\n\n respectivamente. Para fazer esta conexão, os campos são declarados como ponteiros para um node\n\n\n que está vinculado ao tipo T através do uso de colchetes.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype list[T any] struct {\n first *node[T]\n last *node[T]\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O segundo tipo struct é denominado list e representa uma coleção de nodes\n\n\n apontando para o primeiro e o último node de uma lista. Esses campos precisam apontar para um node de\n\n\n algum tipo T, assim como os campos next e prev do tipo node.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Mais uma vez, o identificador T é definido como um tipo genérico (a ser determinado posteriormente)\n\n\n que pode ser substituído por \u0026#34;any\u0026#34; tipo concreto. Então o primeiro e o último campos são\n\n\n declarados como ponteiros para um node de algum tipo T usando a sintaxe de colchetes.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (l *list[T]) add(data T) *node[T] {\n n := node[T]{\n Data: data,\n prev: l.last,\n }\n \n if l.first == nil {\n l.first = \u0026amp;n\n l.last = \u0026amp;n\n return \u0026amp;n\n }\n\n l.last.next = \u0026amp;n\n l.last = \u0026amp;n\n \n return \u0026amp;n\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta é uma implementação de um método chamado add para o tipo list. Não é necessária a declaração de nenhum tipo genérico \n\n\n formal da list (como acontece com funções), pois o método está vinculado à lista por meio do receiver. \n\n\n O receiver do método add é declarado como um ponteiro para uma lista de algum tipo T e\n\n\n o retorno é declarado como um ponteiro para um node do mesmo tipo T.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O código após a construção de um node será sempre o mesmo, independente de\n\n\n que tipo de dados está sendo armazenado na lista, já que isso é apenas manipulação do ponteiro.\n\n\n É apenas a construção de um novo node que é afetada pelo tipo de dados que irá\n\n\n ser gerenciado. Graças a generics, a construção de um node pode ser vinculada ao tipo T\n\n\n que é substituído posteriormente em tempo de compilação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Sem generics, todo este método precisaria ser duplicado, uma vez que o\n\n\n a construção de um node precisaria ser codificada para um tipo conhecido e declarado antes\n\n\n para compilação. Como a quantidade de código (para toda a implementação da lista) que\n\n\n precisa mudar para diferentes tipos de dados é muito pequena, sendo capaz de declarar um nó\n\n\n e lista para gerenciar dados de algum tipo T reduz o custo de duplicação de código e\n\n\n manutenção.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n}\n\nfunc main() {\n // Store values of type user into the list.\n var lv list[user]\n n1 := lv.add(user{\u0026#34;bill\u0026#34;})\n n2 := lv.add(user{\u0026#34;ale\u0026#34;})\n fmt.Println(n1.Data, n2.Data)\n \n // Store pointers of type user into the list.\n var lp list[*user]\n n3 := lp.add(\u0026amp;user{\u0026#34;bill\u0026#34;})\n n4 := lp.add(\u0026amp;user{\u0026#34;ale\u0026#34;})\n fmt.Println(n3.Data, n4.Data)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e{bill} {ale}\n\u0026amp;{bill} \u0026amp;{ale}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui está um pequeno programa. Um tipo chamado user é declarado e então uma lista é\n\n\n construída, em seu estado de \u0026#34;zero value\u0026#34;, para gerenciar valores do tipo user. Uma segunda lista é\n\n\n então construído para seu estado de \u0026#34;zero value\u0026#34; e esta lista gerencia ponteiros para valores do\n\n\n tipo user. A única diferença entre essas duas listas é que uma gerencia valores do\n\n\n tipo user e a outra ponteiros do tipo user.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Como o tipo user é especificado explicitamente durante a construção do tipo list, o método add, \n\n\n por sua vez, aceita valores do tipo user. Como um ponteiro do tipo user é explicitamente\n\n\n especificado durante a construção do tipo de lista, o método add aceita ponteiros do tipo user.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você pode ver na saída do programa, o campo Data para os node nas respectivas\n\n\n listas corresponde à semântica dos dados usada na construção.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare a generic type using a struct type.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n// This code defines two user defined types that implement a linked list. The\n// node type contains data of some type T (to be determined later) and points\n// to other nodes of the same type T. The list type contains pointers to the\n// first and last nodes of some type T. The add method is declared with a\n// pointer receiver based on a list of some type T and is implemented to add\n// nodes to the list of the same type T.\n\ntype node[T any] struct {\n\tData T\n\tnext *node[T]\n\tprev *node[T]\n}\n\ntype list[T any] struct {\n\tfirst *node[T]\n\tlast *node[T]\n}\n\nfunc (l *list[T]) add(data T) *node[T] {\n\tn := node[T]{\n\t\tData: data,\n\t\tprev: l.last,\n\t}\n\tif l.first == nil {\n\t\tl.first = \u0026n\n\t\tl.last = \u0026n\n\t\treturn \u0026n\n\t}\n\tl.last.next = \u0026n\n\tl.last = \u0026n\n\treturn \u0026n\n}\n\n// This user type represents the data to be stored into the linked list.\n\ntype user struct {\n\tname string\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Store values of type user into the list.\n\tvar lv list[user]\n\tn1 := lv.add(user{\"bill\"})\n\tn2 := lv.add(user{\"ale\"})\n\tfmt.Println(n1.Data, n2.Data)\n\n\t// Store pointers of type user into the list.\n\tvar lp list[*user]\n\tn3 := lp.add(\u0026user{\"bill\"})\n\tn4 := lp.add(\u0026user{\"ale\"})\n\tfmt.Println(n3.Data, n4.Data)\n}\n","Hash":"qqvmtPVssHNelLs02Ezd/57oYJo="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para concluir os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declare um tipo genérico chamado stack que usa uma struct com um único\n\n\n campo denominado data, declarado como um slice de algum tipo T. Declare um método\n\n\n chamado push que aceita um valor de algum tipo T e acrescenta o valor ao slice.\n\n\n Declare um método chamado pop que retorne o último valor de\n\n\n algum tipo T que foi acrescentado ao slice e um erro. Então escreva uma função main que usa os métodos.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic stack type.\npackage main\n\n// Declare a generic type named stack that uses a struct with a single\n// field named data declared as a slice of some type T.\n\n// Declare a method named push that accepts a value of some type T and appends\n// the value to the slice.\n\n// Declare a method named pop that returns the latest value of some type T\n// that was appended to the slice and an error.\n\n// =============================================================================\n\nfunc main() {\n\n\t// Constructs a value of type stack that stores integers.\n\n\t// Push the values of 10 and 20 to the stack.\n\n\t// Pop a value from the stack.\n\n\t// Print the value that was popped.\n\n\t// Pop another value from the stack.\n\n\t// Print the value that was popped.\n\n\t// Pop another value from the stack. This should\n\t// return an error.\n}\n","Hash":"T63iw0Q7htkWcGDzxnXDfvYNYJI="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic stack type.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// Declare a generic type named stack that uses a struct with a single\n// field named data declared as a slice of some type T.\ntype stack[T any] struct {\n\tdata []T\n}\n\n// Declare a method named push that accepts a value of some type T and appends\n// the value to the slice.\nfunc (s *stack[T]) push(v T) {\n\ts.data = append(s.data, v)\n}\n\n// Declare a method named pop that returns the latest value of some type T\n// that was appended to the slice and an error.\nfunc (s *stack[T]) pop() (T, error) {\n\tvar zero T\n\n\tif len(s.data) == 0 {\n\t\treturn zero, errors.New(\"stack is empty\")\n\t}\n\n\tv := s.data[len(s.data)-1]\n\n\ts.data = s.data[:len(s.data)-1]\n\n\treturn v, nil\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Constructs a value of type stack that stores integers.\n\tvar s stack[int]\n\n\t// Push the values of 10 and 20 to the stack.\n\ts.push(10)\n\ts.push(20)\n\n\t// Pop a value from the stack.\n\tv, err := s.pop()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\t// Print the value that was popped.\n\tfmt.Println(v)\n\n\t// Pop another value from the stack.\n\tv, err = s.pop()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\t// Print the value that was popped.\n\tfmt.Println(v)\n\n\t// Pop another value from the stack. This should\n\t// return an error.\n\tv, err = s.pop()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n}\n","Hash":"8fTVAz0nMpHCiL1Pc7p+PdHsOtA="}]}]} ,"goroutines":{"Title":"Goroutines","Description":"Goroutines são funções que são criadas e agendadas para serem executadas de forma independente pelo agendador do Go.","Pages":[{"Title":"Goroutines","Content":"\n \u003ch2\u003eGoroutines\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eWatch The Video\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003eNeed Financial Assistance, Use Our \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eScholarship Form\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Goroutines são funções que são criadas e agendadas para serem executadas de forma independente pelo agendador do Go. O agendador do Go é responsável pelo gerenciamento e execução das goroutines.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Goroutines e Concorrência\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Troca de contexto de Goroutine\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Goroutines e Paralelismo\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eSemântica do Agendador\u003c/h2\u003e\n \n \n \u003cp\u003e\n Quando um programa em Go é iniciado, o runtime do Go pergunta à máquina (virtual ou física) quantas threads do sistema operacional podem ser executadas em paralelo. Isso é baseado no número de núcleos disponíveis para o programa. Para cada thread que pode ser executada em paralelo, o runtime cria uma thread do sistema operacional (M) e a associa a uma estrutura de dados que representa um processador lógico (P) dentro do programa. Esse P e M representam a capacidade de cálculo ou contexto de execução para a execução do programa em Go.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Além disso, uma Goroutine inicial (G) é criada para gerenciar a execução das instruções em um M/P selecionado. Assim como um M gerencia a execução das instruções no hardware, um G gerencia a execução das instruções no M. Isso cria uma nova camada de abstração acima do sistema operacional, mas transfere o controle da execução para o nível de aplicação.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/gor1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/gor1.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Uma vez que o agendador do Go fica sobre o agendador do sistema operacional, é importante ter uma compreensão semântica do agendador do sistema operacional e das restrições que ele impõe ao agendador do Go e às aplicações.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O agendador do sistema operacional tem a tarefa de criar a ilusão de que várias tarefas estão sendo executadas ao mesmo tempo, mesmo quando isso é fisicamente impossível. Isso requer algumas compensações no design do agendador. Antes de prosseguir, é importante definir algumas palavras-chave.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eWork:\u003c/b\u003e Um conjunto de instruções a serem executadas por uma aplicação em execução. Isso é realizado por meio de threads, e uma aplicação pode ter de 1 a várias threads.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eThread:\u003c/b\u003e Um caminho de execução que é agendado e executado. As threads são responsáveis pela execução de instruções no hardware.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e*Estados* *da* *Thread:* Uma thread pode estar em um dos três estados: Executando (Running), Pronta para Executar (Runnable) ou Aguardando (Waiting). Executando significa que a thread está executando suas instruções atribuídas no hardware, tendo uma G associada a um M. Pronta para Executar significa que a thread deseja tempo no hardware para executar suas instruções atribuídas e está na fila de execução (run queue). Aguardando significa que a thread está aguardando algo antes de poder retomar seu trabalho. Threads em estado de espera não são uma preocupação do agendador.\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eConcorrência:\u003c/b\u003e Isso significa uma execução indefinida e fora de ordem. Em outras palavras, dado um conjunto de instruções que seriam executadas na ordem fornecida, elas são executadas em uma ordem indefinida diferente, mas todas são executadas. A chave é que o resultado da execução do conjunto completo de instruções em qualquer ordem indefinida produz o mesmo resultado. Pode-se dizer que o trabalho pode ser feito de forma concorrente quando a ordem em que o trabalho é executado não importa, contanto que todo o trabalho seja concluído.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParalelismo:\u003c/b\u003e Isso significa fazer muitas coisas ao mesmo tempo. Para que isso seja uma opção, é necessário ter a capacidade de executar fisicamente duas ou mais threads do sistema operacional ao mesmo tempo no hardware.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eTrabalho\u003c/b\u003e \u003cb\u003eLimitado\u003c/b\u003e \u003cb\u003epela\u003c/b\u003e \u003cb\u003eCPU\u003c/b\u003e \u003cb\u003e(CPU-Bound):\u003c/b\u003e Este é um tipo de trabalho que não faz com que a thread entre naturalmente em um estado de espera. Calcular números de Fibonacci seria considerado um trabalho limitado pela CPU.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eTrabalho\u003c/b\u003e \u003cb\u003eLimitado\u003c/b\u003e \u003cb\u003epor\u003c/b\u003e \u003cb\u003eE/S\u003c/b\u003e \u003cb\u003e(I/O-Bound):\u003c/b\u003e Este é um tipo de trabalho que faz com que a thread entre naturalmente em um estado de espera. Buscar dados de diferentes URLs seria considerado um trabalho limitado por E/S.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eSincronização:\u003c/b\u003e Quando duas ou mais Goroutines precisam acessar a mesma localização de memória potencialmente ao mesmo tempo, elas precisam ser sincronizadas e se revezar. Se essa sincronização não ocorrer e pelo menos uma Goroutine estiver realizando uma escrita, você pode acabar com uma corrida de dados (data race). Corridas de dados são uma causa de bugs de corrupção de dados que podem ser difíceis de encontrar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eOrquestração:\u003c/b\u003e Quando duas ou mais Goroutines precisam sinalizar uma à outra, com ou sem dados, a orquestração é o mecanismo necessário. Se a orquestração não ocorrer, as garantias sobre o trabalho concorrente sendo realizado e concluído podem ser perdidas. Isso pode causar vários tipos de bugs de corrupção de dados.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Há muitos detalhes relacionados às semânticas de agendamento, então, para aprender mais, leia os três posts no capítulo 14 intitulados \u0026#34;Agendamento em Go\u0026#34;.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eFundamentos de Concorrência\u003c/h2\u003e\n \n \n \u003cp\u003e\n Começando com um problema básico de concorrência que requer orquestração.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc init() {\n runtime.GOMAXPROCS(1)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A chamada para \u003ccode\u003eGOMAXPROCS\u003c/code\u003e está sendo usada para executar o programa Go como um programa Go de única thread. Este programa será de única thread e terá apenas um P/M para executar todas as Goroutines. A função está em maiúsculas porque também é uma variável de ambiente. Embora essa chamada de função irá sobrescrever a variável.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eg := runtime.GOMAXPROCS(0)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta função é importante quando você define cotas de CPU para uma configuração de contêiner. Ao passar 0 como argumento, o número de threads que o programa Go usará é relatado. Você deve garantir que esse número corresponda ao número de threads do sistema operacional disponíveis em seu ambiente de contêiner. Se os números não forem os mesmos, o programa Go não funcionará tão bem quanto poderia. Você pode querer usar a variável de ambiente ou esta chamada de função para alinhar essas configurações.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n var wg sync.WaitGroup\n wg.Add(2)\n\n go func() {\n lowercase()\n wg.Done()\n }()\n\n go func() {\n uppercase()\n wg.Done()\n }()\n\n fmt.Println(\u0026#34;Waiting To Finish\u0026#34;)\n wg.Wait()\n\n fmt.Println(\u0026#34;\\nTerminating Program\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este programa precisa resolver um problema de orquestração. A Goroutine principal não pode permitir que a função principal retorne até que haja uma garantia de que as duas Goroutines criadas tenham terminado seu trabalho primeiro. Um WaitGroup é uma ferramenta perfeita para problemas de orquestração que não exigem a passagem de dados entre Goroutines. A sinalização aqui é realizada por meio de uma API que permite que uma Goroutine aguarde outras Goroutines sinalizarem que terminaram.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Neste código, um WaitGroup é construído em seu estado de valor zero e imediatamente o método Add é chamado para definir o WaitGroup como 2, que corresponderá ao número de Goroutines a serem criadas. Quando você sabe quantas Goroutines serão criadas antecipadamente, deve chamar Add uma vez com esse número. Quando você não sabe (como em um serviço de streaming), chamar Add(1) é aceitável.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n No final do main, há uma chamada para Wait. O Wait mantém a Goroutine principal de fazer a função retornar. Quando a função principal retorna, o programa Go é encerrado de forma decisiva. É por isso que gerenciar a orquestração com as garantias adequadas é importante. A chamada para Wait bloqueará até que o WaitGroup seja definido de volta para 0.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n No meio do programa, você tem a criação das duas Goroutines.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n . . .\n\n go func() {\n lowercase()\n wg.Done()\n }()\n\n go func() {\n uppercase()\n wg.Done()\n }()\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Funções literais são declaradas e executadas com o uso da palavra-chave \u003ccode\u003ego\u003c/code\u003e. Neste ponto, você está dizendo ao agendador do Go para executar essas funções concorrentemente, em uma ordem indefinida. Dentro da implementação de cada Goroutine, há a chamada para \u003ccode\u003eDone\u003c/code\u003e. Essa chamada é o que decrementa o WaitGroup em 1. Uma vez que ambas as chamadas para \u003ccode\u003eDone\u003c/code\u003e são feitas, o WaitGroup será alterado de 2 para 0, e então a Goroutine principal será permitida a desbloquear da chamada para \u003ccode\u003eWait\u003c/code\u003e, encerrando o programa.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n var wg sync.WaitGroup\n wg.Add(2)\n\n go func() {\n lowercase()\n wg.Done()\n }()\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Uma parte importante desse padrão de orquestração é manter as chamadas de \u003ccode\u003eAdd\u003c/code\u003e e \u003ccode\u003eDone\u003c/code\u003e no mesmo campo de visão. Tente não passar o WaitGroup como um parâmetro de função onde as chamadas possam se perder. Isso ajudará a reduzir erros.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eResultado:\n\nStart Goroutines\nWaiting To Finish\nA B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z\nTerminating Program\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando você compila e executa este programa, você observa como ele é executado de forma concorrente. A segunda Goroutine criada foi agendada primeiro. Ela conseguiu concluir seu trabalho e, em seguida, a outra Goroutine foi executada. Ambas foram executadas até a conclusão antes que o programa terminasse. Da próxima vez que você executar este programa, não há garantia de que verá a mesma saída. A única garantia neste programa é que ele não terminará até que as duas Goroutines estejam concluídas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Mesmo que você execute este programa 100 vezes e veja a mesma saída, não há garantia de que isso acontecerá novamente. Pode ser altamente provável, mas não garantido. Especialmente não garantido em diferentes versões, sistemas operacionais e arquiteturas.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n . . .\n\n fmt.Println(\u0026#34;Waiting To Finish\u0026#34;)\n // wg.Wait() \u0026lt;-- CHANGED\n\n fmt.Println(\u0026#34;\\nTerminating Program\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Se você comentar a chamada para \u003ccode\u003eWait\u003c/code\u003e, o que acontecerá quando você executar este programa? Mais uma vez, não há garantia alguma do que acontecerá, mas existem diferentes possibilidades.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O programa pode se comportar como antes, uma vez que as chamadas para Println são chamadas de sistema que permitem ao agendador fazer uma troca de contexto. O programa pode executar apenas uma das duas Goroutines ou possivelmente terminar imediatamente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n var wg sync.WaitGroup\n wg.Add(2)\n\n go func() {\n lowercase()\n // wg.Done() \u0026lt;-- CHANGED\n }()\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O que acontece se você esquecer de chamar \u003ccode\u003eDone\u003c/code\u003e em uma das Goroutines? Nesse caso, o programa entraria em deadlock, pois o WaitGroup não poderia ser reduzido para 0. A chamada para Wait ficaria bloqueada indefinidamente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eResultado:\n\nStart Goroutines\nWaiting To Finish\nA B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z\nfatal error: all goroutines are asleep - deadlock!\n\ngoroutine 1 [semacquire]:\nsync.runtime_Semacquire(0xc00001a0a8)\n /usr/local/go/src/runtime/sema.go:56 \u0026#43;0x45\nsync.(*WaitGroup).Wait(0xc00001a0a0)\n /usr/local/go/src/sync/waitgroup.go:130 \u0026#43;0x65\nmain.main()\n concurrency/goroutines/example1/example1.go:42 \u0026#43;0x145\nexit status 2\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver como o runtime do Go identifica que o programa está em deadlock na linha 42, onde a chamada para Wait está ocorrendo. No entanto, não fique muito empolgado com a detecção de deadlock, pois cada Goroutine precisa estar bloqueada sem nenhuma saída. Isso demonstra por que é tão importante manter as chamadas de Add e Done juntas.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n var wg sync.WaitGroup\n wg.Add(1) \u0026lt;-- CHANGED, Number Too Small\n\n go func() {\n lowercase()\n wg.Done()\n }()\n\n go func() {\n uppercase()\n wg.Done()\n }()\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O que acontece se você não fornecer ao WaitGroup o número correto de Goroutines para aguardar? Se o número for muito grande, você terá outro deadlock. Se o número for muito pequeno, não há garantias de que o trabalho seja concluído antes que o programa prossiga. A saída do programa é indefinida.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eAgendador Preemptivo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Mesmo que o agendador seja executado dentro do escopo da aplicação, é importante entender como o agendamento é preemptivo. Isso significa que você não pode prever quando ocorrerá uma troca de contexto, e isso mudará toda vez que você executar o programa.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n var wg sync.WaitGroup\n wg.Add(2)\n\n go func() {\n printHashes(\u0026#34;A\u0026#34;)\n wg.Done()\n }()\n\n go func() {\n printHashes(\u0026#34;B\u0026#34;)\n wg.Done()\n }()\n\n fmt.Println(\u0026#34;Waiting To Finish\u0026#34;)\n wg.Wait()\n\n fmt.Println(\u0026#34;\\nTerminating Program\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Usando o mesmo padrão de orquestração como antes, este programa faz com que cada Goroutine realize um trabalho muito mais extenso. Um trabalho que o agendador não dará à Goroutine tempo suficiente para concluir completamente em um único intervalo de tempo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc printHashes(prefix string) {\n for i := 1; i \u0026lt;= 50000; i\u0026#43;\u0026#43; {\n num := strconv.Itoa(i)\n sum := sha1.Sum([]byte(num))\n fmt.Printf(\u0026#34;%s: %05d: %x\\n\u0026#34;, prefix, i, sum)\n }\n fmt.Println(\u0026#34;Completed\u0026#34;, prefix)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta função está realizando um trabalho muito relacionado à E/S (Entrada/Saída) que tem o potencial de ser interrompido por trocas de contexto.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e$ ./example2 | cut -c1 | grep \u0026#39;[AB]\u0026#39; | uniq\nB\nA\nB\nA\nB\nA\nB\nA\nB\nA 9 Context Switches\n\n$ ./example2 | cut -c1 | grep \u0026#39;[AB]\u0026#39; | uniq\nB\nA\nB\nA 3 Context Switches\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Como você pode ver, cada vez que você executa o programa, há um número diferente de trocas de contexto. Isso é algo positivo, pois um agendador não deve ser previsível. A concorrência precisa permanecer indefinida, e você deve se lembrar disso quando usar a concorrência para resolver seus problemas de desempenho.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc init() {\n runtime.GOMAXPROCS(2)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O que acontece se você voltar ao programa original, mas alterar o \u003ccode\u003eGOMAXPROCS\u003c/code\u003e para que o programa seja executado como um programa Go com duas threads?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eResultado:\n\nStart Goroutines\nWaiting To Finish\nA B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N a b c d e f g h i j k l m n o O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z\nTerminating Program\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O que você observa é que a concorrência do programa agora está mais refinada. A saída, ao pé da letra, é indefinida e fora de ordem.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eGoroutines são funções agendadas para serem executadas independentemente.\u003c/li\u003e\n \n \u003cli\u003eDevemos sempre manter um registro das goroutines em execução e encerrar de forma limpa.\u003c/li\u003e\n \n \u003cli\u003eConcorrência não é paralelismo.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \u003cul\u003e\n \n \u003cli\u003eConcorrência trata de lidar com muitas coisas ao mesmo tempo.\u003c/li\u003e\n \n \u003cli\u003eParalelismo trata de fazer muitas coisas ao mesmo tempo.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u0026#34;Paralelismo trata de fazer fisicamente duas ou mais coisas ao mesmo tempo. Concorrência trata de uma execução indefinida e fora de ordem.\u0026#34; - William Kennedy\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Por padrão, as goroutines não devem sobreviver à função da qual foram criadas. Isso o força a adotar uma postura de design extremamente boa.\u0026#34; - Peter Bourgon\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eOrientações de Design\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eAprenda sobre o \u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/go/#concurrent-software-design\" target=\"_blank\"\u003edesign guidelines\u003c/a\u003e para concorrência.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part1.html\" target=\"_blank\"\u003eScheduling In Go - Part I\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html\" target=\"_blank\"\u003eScheduling In Go - Part II\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2015/02/scheduler-tracing-in-go.html\" target=\"_blank\"\u003eScheduler Tracing In Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/advanced-go-concurrency-patterns\" target=\"_blank\"\u003eAdvanced Go Concurrency Patterns\u003c/a\u003e - Sameer Ajmani \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/context\" target=\"_blank\"\u003eGo Concurrency Patterns: Context\u003c/a\u003e - Sameer Ajmani \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/concurrency-is-not-parallelism\" target=\"_blank\"\u003eConcurrency is not parallelism\u003c/a\u003e - Rob Pike \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://talks.golang.org/2013/distsys.slide\" target=\"_blank\"\u003eGo, for Distributed Systems\u003c/a\u003e - Russ Cox \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://docs.google.com/document/d/1At2Ls5_fhJQ59kDK2DFVhFu3g5mATSXqqV5QrxinasI/edit\" target=\"_blank\"\u003eGo 1.5 GOMAXPROCS Default\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/01/concurrency-goroutines-and-gomaxprocs.html\" target=\"_blank\"\u003eConcurrency, Goroutines and GOMAXPROCS\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.ece.ubc.ca/~sasha/papers/eurosys16-final29.pdf\" target=\"_blank\"\u003eThe Linux Scheduler: a Decade of Wasted Cores\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://news.ycombinator.com/item?id=12460807\" target=\"_blank\"\u003eExplanation of the Scheduler\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://joeduffyblog.com/2016/11/30/15-years-of-concurrency/\" target=\"_blank\"\u003e15 Years of Concurrency\u003c/a\u003e - Joe Duffy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.quora.com/How-does-the-golang-scheduler-work/answer/Ian-Lance-Taylor\" target=\"_blank\"\u003eHow does the golang scheduler work?\u003c/a\u003e - Ian Lance Taylor \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=YHRO5WQGh0k\" target=\"_blank\"\u003eThe Scheduler Saga\u003c/a\u003e - Kavya Joshi \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to create goroutines and\n// how the scheduler behaves.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n)\n\nfunc init() {\n\n\t// Allocate one logical processor for the scheduler to use.\n\truntime.GOMAXPROCS(1)\n}\n\nfunc main() {\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(2)\n\n\tfmt.Println(\"Start Goroutines\")\n\n\t// Create a goroutine from the lowercase function.\n\tgo func() {\n\t\tlowercase()\n\t\twg.Done()\n\t}()\n\n\t// Create a goroutine from the uppercase function.\n\tgo func() {\n\t\tuppercase()\n\t\twg.Done()\n\t}()\n\n\t// Wait for the goroutines to finish.\n\tfmt.Println(\"Waiting To Finish\")\n\twg.Wait()\n\n\tfmt.Println(\"\\nTerminating Program\")\n}\n\n// lowercase displays the set of lowercase letters three times.\nfunc lowercase() {\n\n\t// Display the alphabet three times\n\tfor count := 0; count \u003c 3; count++ {\n\t\tfor r := 'a'; r \u003c= 'z'; r++ {\n\t\t\tfmt.Printf(\"%c \", r)\n\t\t}\n\t}\n}\n\n// uppercase displays the set of uppercase letters three times.\nfunc uppercase() {\n\n\t// Display the alphabet three times\n\tfor count := 0; count \u003c 3; count++ {\n\t\tfor r := 'A'; r \u003c= 'Z'; r++ {\n\t\t\tfmt.Printf(\"%c \", r)\n\t\t}\n\t}\n}\n","Hash":"RBkebacNV6jryrcGxd2wp1bPmdI="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// $ ./example2 | cut -c1 | grep '[AB]' | uniq\n\n// Sample program to show how the goroutine scheduler\n// will time slice goroutines on a single thread.\npackage main\n\nimport (\n\t\"crypto/sha1\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"sync\"\n)\n\nfunc init() {\n\n\t// Allocate one logical processor for the scheduler to use.\n\truntime.GOMAXPROCS(1)\n}\n\nfunc main() {\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(2)\n\n\tfmt.Println(\"Create Goroutines\")\n\n\t// Create the first goroutine and manage its lifecycle here.\n\tgo func() {\n\t\tprintHashes(\"A\")\n\t\twg.Done()\n\t}()\n\n\t// Create the second goroutine and manage its lifecycle here.\n\tgo func() {\n\t\tprintHashes(\"B\")\n\t\twg.Done()\n\t}()\n\n\t// Wait for the goroutines to finish.\n\tfmt.Println(\"Waiting To Finish\")\n\twg.Wait()\n\n\tfmt.Println(\"Terminating Program\")\n}\n\n// printHashes calculates the sha1 hash for a range of\n// numbers and prints each in hex encoding.\nfunc printHashes(prefix string) {\n\n\t// print each has from 1 to 10. Change this to 50000 and\n\t// see how the scheduler behaves.\n\tfor i := 1; i \u003c= 50000; i++ {\n\n\t\t// Convert i to a string.\n\t\tnum := strconv.Itoa(i)\n\n\t\t// Calculate hash for string num.\n\t\tsum := sha1.Sum([]byte(num))\n\n\t\t// Print prefix: 5-digit-number: hex encoded hash\n\t\tfmt.Printf(\"%s: %05d: %x\\n\", prefix, i, sum)\n\t}\n\n\tfmt.Println(\"Completed\", prefix)\n}\n","Hash":"Pnx/XFZipGeRP6kyw0DTx0LIlqA="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to create goroutines and\n// how the goroutine scheduler behaves with two contexts.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n)\n\nfunc init() {\n\n\t// Allocate two logical processors for the scheduler to use.\n\truntime.GOMAXPROCS(2)\n}\n\nfunc main() {\n\n\t// wg is used to wait for the program to finish.\n\t// Add a count of two, one for each goroutine.\n\tvar wg sync.WaitGroup\n\twg.Add(2)\n\n\tfmt.Println(\"Start Goroutines\")\n\n\t// Declare an anonymous function and create a goroutine.\n\tgo func() {\n\n\t\t// Display the alphabet three times.\n\t\tfor count := 0; count \u003c 3; count++ {\n\t\t\tfor r := 'a'; r \u003c= 'z'; r++ {\n\t\t\t\tfmt.Printf(\"%c \", r)\n\t\t\t}\n\t\t}\n\n\t\t// Tell main we are done.\n\t\twg.Done()\n\t}()\n\n\t// Declare an anonymous function and create a goroutine.\n\tgo func() {\n\n\t\t// Display the alphabet three times.\n\t\tfor count := 0; count \u003c 3; count++ {\n\t\t\tfor r := 'A'; r \u003c= 'Z'; r++ {\n\t\t\t\tfmt.Printf(\"%c \", r)\n\t\t\t}\n\t\t}\n\n\t\t// Tell main we are done.\n\t\twg.Done()\n\t}()\n\n\t// Wait for the goroutines to finish.\n\tfmt.Println(\"Waiting To Finish\")\n\twg.Wait()\n\n\tfmt.Println(\"\\nTerminating Program\")\n}\n","Hash":"PpFAV7bqjIDOGzz7fbXXGTMRjvo="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para concluir os exercícios. Uma solução possível é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA\u003c/b\u003e Crie um programa que declare duas funções anônimas. Uma que conte de 100 até 0 e outra que conte de 0 até 100. Exiba cada número com um identificador exclusivo para cada goroutine. Em seguida, crie goroutines a partir dessas funções e não permita que a função principal retorne até que as goroutines terminem.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB\u003c/b\u003e Execute o programa em paralelo.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create a program that declares two anonymous functions. One that counts down from\n// 100 to 0 and one that counts up from 0 to 100. Display each number with an\n// unique identifier for each goroutine. Then create goroutines from these functions\n// and don't let main return until the goroutines complete.\n//\n// Run the program in parallel.\npackage main\n\n// Add imports.\nimport \"runtime\"\n\nfunc init() {\n\n\t// Allocate one logical processor for the scheduler to use.\n\truntime.GOMAXPROCS(1)\n}\n\nfunc main() {\n\n\t// Declare a wait group and set the count to two.\n\n\t// Declare an anonymous function and create a goroutine.\n\t{\n\t\t// Declare a loop that counts down from 100 to 0 and\n\t\t// display each value.\n\n\t\t// Tell main we are done.\n\t}\n\n\t// Declare an anonymous function and create a goroutine.\n\t{\n\t\t// Declare a loop that counts up from 0 to 100 and\n\t\t// display each value.\n\n\t\t// Tell main we are done.\n\t}\n\n\t// Wait for the goroutines to finish.\n\n\t// Display \"Terminating Program\".\n}\n","Hash":"Aax+V6i/e9lPdY/epDpuTQq0S8I="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create a program that declares two anonymous functions. One that counts down from\n// 100 to 0 and one that counts up from 0 to 100. Display each number with an\n// unique identifier for each goroutine. Then create goroutines from these functions\n// and don't let main return until the goroutines complete.\n//\n// Run the program in parallel.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n)\n\nfunc init() {\n\n\t// Allocate one logical processor for the scheduler to use.\n\truntime.GOMAXPROCS(1)\n}\n\nfunc main() {\n\n\t// Declare a wait group and set the count to two.\n\tvar wg sync.WaitGroup\n\twg.Add(2)\n\n\tfmt.Println(\"Start Goroutines\")\n\n\t// Declare an anonymous function and create a goroutine.\n\tgo func() {\n\t\t// Count down from 100 to 0.\n\t\tfor count := 100; count \u003e= 0; count-- {\n\t\t\tfmt.Printf(\"[A:%d]\\n\", count)\n\t\t}\n\n\t\t// Tell main we are done.\n\t\twg.Done()\n\t}()\n\n\t// Declare an anonymous function and create a goroutine.\n\tgo func() {\n\t\t// Count up from 0 to 100.\n\t\tfor count := 0; count \u003c= 100; count++ {\n\t\t\tfmt.Printf(\"[B:%d]\\n\", count)\n\t\t}\n\n\t\t// Tell main we are done.\n\t\twg.Done()\n\t}()\n\n\t// Wait for the goroutines to finish.\n\tfmt.Println(\"Waiting To Finish\")\n\twg.Wait()\n\n\t// Display \"Terminating Program\".\n\tfmt.Println(\"\\nTerminating Program\")\n}\n","Hash":"ZHF97i+9MwB5y7rZc/nXSyhw/40="}]}]} ,"composition-mocking":{"Title":"Mocking","Description":"Uma vez que o compilador pode executar análise estática de código para determinar se um valor concreto implementa uma interface, o desenvolvedor que declarou o tipo concreto não precisa fornecer a interface também.","Pages":[{"Title":"Mocking","Content":"\n \u003ch2\u003eMocking\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n A melhor maneira de se aproveitar a encorporação, é através do padrão de composição. \n\n\n A ideia é compor tipos maiores a partir de tipos menores e focar na composição do comportamento.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Mocking\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003ePropriedade da Interface\u003c/h2\u003e\n \n \n \u003cp\u003e\n Uma coisa que difere Go das outras linguagens é a ideia de convenção sobre configuração. \n\n\n Isso realmente fica a mostra na maneira que Go lida com a conformidade de interfaces.\n\n\n Porque o compilador pode executar uma análise estática de código para determinar se um valor concreto\n\n\n implementa uma interface, o desenvolvedor declarando o tipo concreto não precisa fornecer a interface também.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage pubsub\n\ntype PubSub struct {\n host string\n}\n\nfunc New(host string) *PubSub {\n return \u0026amp;PubSub{\n host: host,\n }\n}\n\nfunc (ps *PubSub) Publish(key string, v interface{}) error {\n // IMPLEMENTAÇÃO FANTÁSTICA AQUI.\n return nil\n}\n\nfunc (ps *PubSub) Subscribe(key string) error {\n // IMPLEMENTAÇÃO FANTÁSTICA AQUI.\n return nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você acabou de implementar uma nova API que fornece uma implementação concreta para \n\n\n publicação e assinatura (pub/sub). Não há interfaces sendo fornecidas porque essa API \n\n\n não necessita de uma interface. Essa é a única implementação concreta.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Mas e se o desenvolvedor da aplicação querendo usar essa nova API, necessita da interface \n\n\n porque ele sente a necessidade de criar um \u003ccode\u003emock\u003c/code\u003e dessa implementação durante os testes? \n\n\n Em Go, esse desenvolvedor pode declarar a interface e o compilador pode identificar a conformidade.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage main\n\ntype publisher interface {\n Publish(key string, v interface{}) error\n Subscribe(key string) error\n}\n\ntype mock struct{}\n\nfunc (m *mock) Publish(key string, v interface{}) error {\n // AQUI VAI O `MOCK` QUE CHAMA A FUNÇÃO `PUBLISH`.\n return nil\n}\n\nfunc (m *mock) Subscribe(key string) error {\n // AQUI VAI O `MOCK` QUE CHAMA A FUNÇÃO `SUBSCRIBE`.\n return nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esse código no pacote \u003ccode\u003emain\u003c/code\u003e esta declarando uma interface. Essa interface representa \n\n\n a API que a aplicação está usando do pacote \u003ccode\u003epubsub\u003c/code\u003e. O desenvolvedor implementou sua versão própria\n\n\n de um pubsub para testes. O ponto chave é que esse desenvolvedor não usa nenhuma implementação concreta diretamente,\n\n\n mas se desacopla através de sua interface própria.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n pubs := []publisher{\n pubsub.New(\u0026#34;localhost\u0026#34;),\n \u0026amp;mock{},\n }\n\n for _, p := range pubs {\n p.Publish(\u0026#34;key\u0026#34;, \u0026#34;value\u0026#34;)\n p.Subscribe(\u0026#34;key\u0026#34;)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Como exemplo, a função main constrói uma coleção que é inicializada com a implementação do \u003ccode\u003epubsub\u003c/code\u003e \n\n\n e a implementação do \u003ccode\u003emock\u003c/code\u003e. A interface do \u003ccode\u003epublisher\u003c/code\u003e permite isso. Utilizamos um `for range loop` para mostrar como \n\n\n o código da aplicação é abstraída de sua implementação concreta.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how you can personally mock concrete types when\n// you need to for your own packages or tests.\npackage main\n\nimport (\n\t\"play.ground/pubsub\"\n)\n\n// publisher is an interface to allow this package to mock the pubsub\n// package support.\ntype publisher interface {\n\tPublish(key string, v interface{}) error\n\tSubscribe(key string) error\n}\n\n// =============================================================================\n\n// mock is a concrete type to help support the mocking of the pubsub package.\ntype mock struct{}\n\n// Publish implements the publisher interface for the mock.\nfunc (m *mock) Publish(key string, v interface{}) error {\n\n\t// ADD YOUR MOCK FOR THE PUBLISH CALL.\n\treturn nil\n}\n\n// Subscribe implements the publisher interface for the mock.\nfunc (m *mock) Subscribe(key string) error {\n\n\t// ADD YOUR MOCK FOR THE SUBSCRIBE CALL.\n\treturn nil\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Create a slice of publisher interface values. Assign\n\t// the address of a pubsub.PubSub value and the address of\n\t// a mock value.\n\tpubs := []publisher{\n\t\tpubsub.New(\"localhost\"),\n\t\t\u0026mock{},\n\t}\n\n\t// Range over the interface value to see how the publisher\n\t// interface provides the level of decoupling the user needs.\n\t// The pubsub package did not need to provide the interface type.\n\tfor _, p := range pubs {\n\t\tp.Publish(\"key\", \"value\")\n\t\tp.Subscribe(\"key\")\n\t}\n}\n\n// -----------------------------------------------------------------------------\n-- pubsub/pubsub.go --\n\n// Package pubsub simulates a package that provides publication/subscription\n// type services.\npackage pubsub\n\n// PubSub provides access to a queue system.\ntype PubSub struct {\n\thost string\n\n\t// PRETEND THERE ARE MORE FIELDS.\n}\n\n// New creates a pubsub value for use.\nfunc New(host string) *PubSub {\n\tps := PubSub{\n\t\thost: host,\n\t}\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\n\treturn \u0026ps\n}\n\n// Publish sends the data for the specified key.\nfunc (ps *PubSub) Publish(key string, v interface{}) error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\n// Subscribe sets up an request to receive messages for the specified key.\nfunc (ps *PubSub) Subscribe(key string) error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\n// -----------------------------------------------------------------------------\n-- go.mod --\n \nmodule \"play.ground\"\n\ngo 1.24.0\n","Hash":"wssSd4UC5vQCGhI8HTaOsVwMjDw="}]}]} ,"algorithms-bits-seven":{"Title":"Operações com Bits","Description":"Essa seção fornece exemplos que executam operações com bits.","Pages":[{"Title":"É Par Ou Ímpar","Content":"\n \u003ch2\u003eÉ Par Ou Ímpar\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Esse programa de exemplo mostra como verificar se um inteiro é par ou ímpar\n\n\n utilizando manipulação de bits.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"iseven.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to check if an integer is even or\n// odd using bit manipulation.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tfmt.Println(8, \":\", IsEven(8))\n\tfmt.Println(15, \":\", IsEven(15))\n\tfmt.Println(4, \":\", IsEven(4))\n}\n\n// IsEven checks is an integer is even.\nfunc IsEven(num int) bool {\n\n\t// Use the bitwise AND operator to see if the least significant\n\t// bit (LSB) is 0.\n\n\t// Helpful source: https://catonmat.net/low-level-bit-hacks\n\t// 0 \u0026 1 = 0 (even number)\n\t// 1 \u0026 1 = 1 (odd number)\n\n\treturn num\u00261 == 0\n}\n","Hash":"xOgl65Wqk/qcXxDKTqS7WCJcrz8="}]}]} ,"algorithms-data":{"Title":"Estruturas de Dados","Description":"Essa seção fornece exemplos de estruturas de dados.","Pages":[{"Title":"Hash Map","Content":"\n \u003ch2\u003eHash Map\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Este programa de exemplo implementa uma tabela hash básica.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003ehashKey(key) retorna um número entre 0 e len(buckets)-1\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \u003cul\u003e\n \n \u003cli\u003eNós usamos uma slice de entries como um bucket para lidar com casos em que\na hash de duas ou mais chaves são mapeadas para o mesmo bucket.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Hash_table\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Hash_table\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eCom um hash map, os dados são indexados por bucket e então\npela posição dentro do bucket.\n\nhashKey(key) ──────────────┐\n │\n ▽\n ┌────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐\n │ │ │ │ │ │ │ │ │ ◁── bucket\n └────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘\n │ │\n ▽ ▽\n ┌─────────────┐ ┌─────────────┐\n │ key │ value │ │ key │ value │ ◁── entry\n ├─────────────┤ ├─────────────┤\n │ key │ value │ │ key │ value │\n ├─────────────┤ └─────────────┘\n │ key │ value │\n ├─────────────┤\n │ key │ value │\n ├─────────────┤\n │ key │ value │\n └─────────────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"hash_map.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a basic hash table.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"hash/maphash\"\n)\n\nfunc main() {\n\th := New()\n\n\tk1, v1 := \"key1\", 1\n\tk2, v2 := \"key2\", 2\n\th.Store(k1, v1)\n\th.Store(k2, v2)\n\n\tv, err := h.Retrieve(k1)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"key:\", k1, \"value:\", v)\n\n\tv1b := 11\n\th.Store(k1, v1b)\n\n\tv, err = h.Retrieve(k1)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"key:\", k1, \"value:\", v)\n\n\tif err := h.Delete(k1); err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tv, err = h.Retrieve(k1)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\tfn := func(key string, value int) bool {\n\t\tfmt.Println(\"key:\", key, \"value:\", value)\n\t\treturn true\n\t}\n\th.Do(fn)\n}\n\n// =============================================================================\n\nconst numBuckets = 256\n\n// An entry where we store key and value in the hash.\ntype entry struct {\n\tkey string\n\tvalue int\n}\n\n// Hash is a simple Hash table implementation.\ntype Hash struct {\n\tbuckets [][]entry\n\thash maphash.Hash\n}\n\n// New returns a new hash table.\nfunc New() *Hash {\n\treturn \u0026Hash{\n\t\tbuckets: make([][]entry, numBuckets),\n\t}\n}\n\n// Store adds a value in the hash table based on the key.\nfunc (h *Hash) Store(key string, value int) {\n\n\t// For the specified key, identify what bucket in\n\t// the slice we need to store the key/value inside of.\n\tidx := h.hashKey(key)\n\n\t// Extract a copy of the bucket from the hash table.\n\tbucket := h.buckets[idx]\n\n\t// Iterate over the indexes for the specified bucket.\n\tfor idx := range bucket {\n\n\t\t// Compare the keys and if there is a match replace the\n\t\t// existing entry value for the new value.\n\t\tif bucket[idx].key == key {\n\t\t\tbucket[idx].value = value\n\t\t\treturn\n\t\t}\n\t}\n\n\t// This key does not exist, so add this new value.\n\th.buckets[idx] = append(bucket, entry{key, value})\n}\n\n// Retrieve extracts a value from the hash table based on the key.\nfunc (h *Hash) Retrieve(key string) (int, error) {\n\n\t// For the specified key, identify what bucket in\n\t// the slice we need to store the key/value inside of.\n\tidx := h.hashKey(key)\n\n\t// Iterate over the entries for the specified bucket.\n\tfor _, entry := range h.buckets[idx] {\n\n\t\t// Compare the keys and if there is a match return\n\t\t// the value associated with the key.\n\t\tif entry.key == key {\n\t\t\treturn entry.value, nil\n\t\t}\n\t}\n\n\t// The key was not found so return the error.\n\treturn 0, fmt.Errorf(\"%q not found\", key)\n}\n\n// Delete deletes an entry from the hash table.\nfunc (h *Hash) Delete(key string) error {\n\n\t// For the specified key, identify what bucket in\n\t// the slice we need to store the key/value inside of.\n\tbucketIdx := h.hashKey(key)\n\n\t// Extract a copy of the bucket from the hash table.\n\tbucket := h.buckets[bucketIdx]\n\n\t// Iterate over the entries for the specified bucket.\n\tfor entryIdx, entry := range bucket {\n\n\t\t// Compare the keys and if there is a match remove\n\t\t// the entry from the bucket.\n\t\tif entry.key == key {\n\n\t\t\t// Remove the entry based on its index position.\n\t\t\tbucket = removeEntry(bucket, entryIdx)\n\n\t\t\t// Replace the existing bucket for the new one.\n\t\t\th.buckets[bucketIdx] = bucket\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// The key was not found so return the error.\n\treturn fmt.Errorf(\"%q not found\", key)\n}\n\n// Len return the number of elements in the hash. This function currently\n// uses a linear traversal but could be improved with meta-data.\nfunc (h *Hash) Len() int {\n\tsum := 0\n\tfor _, bucket := range h.buckets {\n\t\tsum += len(bucket)\n\t}\n\treturn sum\n}\n\n// Do calls fn on each key/value. If fn return false stops the iteration.\nfunc (h *Hash) Do(fn func(key string, value int) bool) {\n\tfor _, bucket := range h.buckets {\n\t\tfor _, entry := range bucket {\n\t\t\tif ok := fn(entry.key, entry.value); !ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// hashKey calculates the bucket index position to use\n// for the specified key.\nfunc (h *Hash) hashKey(key string) int {\n\n\t// Reset the maphash to initial state so we'll get the same\n\t// hash value for the same key.\n\th.hash.Reset()\n\n\t// Write the key to the maphash to update the current state.\n\t// We don't check error value since WriteString never fails.\n\th.hash.WriteString(key)\n\n\t// Ask the maphash for its current state which we will\n\t// use to calculate the final bucket index.\n\tn := h.hash.Sum64()\n\n\t// Use the modulus operator to return a value in the range\n\t// of our bucket length defined by the const numBuckets.\n\treturn int(n % numBuckets)\n}\n\n// removeEntry performs the physical act of removing an\n// entry from a bucket,\nfunc removeEntry(bucket []entry, idx int) []entry {\n\n\t// https://github.com/golang/go/wiki/SliceTricks\n\t// Cut out the entry by taking all entries from\n\t// infront of the index and moving them behind the\n\t// index specified.\n\tcopy(bucket[idx:], bucket[idx+1:])\n\n\t// Set the proper length for the new slice since\n\t// an entry was removed. The length needs to be\n\t// reduced by 1.\n\tbucket = bucket[:len(bucket)-1]\n\n\t// Look to see if the current allocation for the\n\t// bucket can be reduced due to the amount of\n\t// entries removed from this bucket.\n\treturn reduceAllocation(bucket)\n}\n\n// reduceAllocation looks to see if memory can be freed to\n// when a bucket has lost a percent of entries.\nfunc reduceAllocation(bucket []entry) []entry {\n\n\t// If the bucket if more than ½ full, do nothing.\n\tif cap(bucket) \u003c 2*len(bucket) {\n\t\treturn bucket\n\t}\n\n\t// Free memory when the bucket shrinks a lot. If we don't do that,\n\t// the underlying bucket array will stay in memory and will be in\n\t// the biggest size the bucket ever was\n\tnewBucket := make([]entry, len(bucket))\n\tcopy(newBucket, bucket)\n\treturn newBucket\n}\n","Hash":"t0was3T0R0/iciXY8DmChdEtlRo="}]},{"Title":"Lista Encadeada ou Lista Ligada","Content":"\n \u003ch2\u003eLista Encadeada ou Lista Ligada\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este programa de exemplo implementa uma lista duplamente encadeada básica.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Linked_list\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Linked_list\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eCom uma lista encadeada, os valores ficam em diferentes locais\nda memória e são vinculados por meio do uso de ponteiros.\n\n┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐\n│ Val │ ◁─▷ │ Val │ ◁─▷ │ Val │ ◁─▷ │ Val │ ◁─▷ │ Val │\n└─────┘ └─────┘ └─────┘ └─────┘ └─────┘\n △ △\n │ │\n ──────────────────── ─────────────────────\n │ │\n │ │\n ┌───────────────┐\n │ First │ Last │\n └───────────────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"list.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a basic double linked list.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc main() {\n\tvar l List\n\n\tconst nodes = 5\n\tfor i := 0; i \u003c nodes; i++ {\n\t\tdata := fmt.Sprintf(\"Node%d\", i)\n\t\tl.Add(data)\n\t}\n\n\tf := func(n *Node) error {\n\t\tfmt.Println(\"Data:\", n.Data)\n\t\treturn nil\n\t}\n\n\tl.Operate(f)\n\n\tfmt.Println(\"------------------\")\n\n\tl.OperateReverse(f)\n}\n\n// =============================================================================\n\n// Node represents the data being stored.\ntype Node struct {\n\tData string\n\tnext *Node\n\tprev *Node\n}\n\n// List represents a list of nodes.\ntype List struct {\n\tCount int\n\tfirst *Node\n\tlast *Node\n}\n\n// Add places a new node at the end of the list.\nfunc (l *List) Add(data string) *Node {\n\n\t// When creating the new node, have the new node\n\t// point to the last node in the list.\n\tn := Node{\n\t\tData: data,\n\t\tprev: l.last,\n\t}\n\n\t// Increment the count for the new node.\n\tl.Count++\n\n\t// If this is the first node, attach it.\n\tif l.first == nil \u0026\u0026 l.last == nil {\n\t\tl.first = \u0026n\n\t\tl.last = \u0026n\n\t\treturn \u0026n\n\t}\n\n\t// Fix the fact that the last node does not point back to\n\t// the NEW node.\n\tl.last.next = \u0026n\n\n\t// Fix the fact the Last pointer is not pointing to the true\n\t// end of the list.\n\tl.last = \u0026n\n\n\treturn \u0026n\n}\n\n// AddFront places a new node at the front of the list.\nfunc (l *List) AddFront(data string) *Node {\n\n\t// When creating the new node, have the new node\n\t// point to the first node in the list.\n\tn := Node{\n\t\tData: data,\n\t\tnext: l.first,\n\t}\n\n\t// Increment the count for the new node.\n\tl.Count++\n\n\t// If this is the first node, attach it.\n\tif l.first == nil \u0026\u0026 l.last == nil {\n\t\tl.first = \u0026n\n\t\tl.last = \u0026n\n\t\treturn \u0026n\n\t}\n\n\t// Fix the fact that the first node does not point back to\n\t// the NEW node.\n\tl.first.prev = \u0026n\n\n\t// Fix the fact the First pointer is not pointing to the true\n\t// beginning of the list.\n\tl.first = \u0026n\n\n\treturn \u0026n\n}\n\n// Find traverses the list looking for the specified data.\nfunc (l *List) Find(data string) (*Node, error) {\n\tn := l.first\n\tfor n != nil {\n\t\tif n.Data == data {\n\t\t\treturn n, nil\n\t\t}\n\t\tn = n.next\n\t}\n\treturn nil, fmt.Errorf(\"unable to locate %q in list\", data)\n}\n\n// FindReverse traverses the list in the opposite direction\n// looking for the specified data.\nfunc (l *List) FindReverse(data string) (*Node, error) {\n\tn := l.last\n\tfor n != nil {\n\t\tif n.Data == data {\n\t\t\treturn n, nil\n\t\t}\n\t\tn = n.prev\n\t}\n\treturn nil, fmt.Errorf(\"unable to locate %q in list\", data)\n}\n\n// Remove traverses the list looking for the specified data\n// and if found, removes the node from the list.\nfunc (l *List) Remove(data string) (*Node, error) {\n\tn, err := l.Find(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Detach the node by linking the previous node's next\n\t// pointer to the node in front of the one being removed.\n\tn.prev.next = n.next\n\tn.next.prev = n.prev\n\tl.Count--\n\n\treturn n, nil\n}\n\n// Operate accepts a function that takes a node and calls\n// the specified function for every node found.\nfunc (l *List) Operate(f func(n *Node) error) error {\n\tn := l.first\n\tfor n != nil {\n\t\tif err := f(n); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn = n.next\n\t}\n\treturn nil\n}\n\n// OperateReverse accepts a function that takes a node and\n// calls the specified function for every node found.\nfunc (l *List) OperateReverse(f func(n *Node) error) error {\n\tn := l.last\n\tfor n != nil {\n\t\tif err := f(n); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn = n.prev\n\t}\n\treturn nil\n}\n\n// AddSort adds a node based on lexical ordering.\nfunc (l *List) AddSort(data string) *Node {\n\n\t// If the list was empty add the data\n\t// as the first node.\n\tif l.first == nil {\n\t\treturn l.Add(data)\n\t}\n\n\t// Traverse the list looking for placement.\n\tn := l.first\n\tfor n != nil {\n\n\t\t// If this data is greater than the current node,\n\t\t// keep traversing until it is less than or equal.\n\t\tif strings.Compare(data, n.Data) \u003e 0 {\n\t\t\tn = n.next\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create the new node and place it before the\n\t\t// current node.\n\t\tnew := Node{\n\t\t\tData: data,\n\t\t\tnext: n,\n\t\t\tprev: n.prev,\n\t\t}\n\n\t\tl.Count++\n\n\t\t// If this node is now to be the first,\n\t\t// fix the first pointer.\n\t\tif l.first == n {\n\t\t\tl.first = \u0026new\n\t\t}\n\n\t\t// If the current node points to a previous node,\n\t\t// then that previous nodes next must point to the\n\t\t// new node.\n\t\tif n.prev != nil {\n\t\t\tn.prev.next = \u0026new\n\t\t}\n\n\t\t// The current previous points must point back\n\t\t// to this new node.\n\t\tn.prev = \u0026new\n\n\t\treturn n\n\t}\n\n\t// This must be the largest string, so add to the end.\n\treturn l.Add(data)\n}\n","Hash":"bQ9fyslwgD9Gc3fAHR1MFfqYIu8="}]},{"Title":"Fila","Content":"\n \u003ch2\u003eFila\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este programa de exemplo implementa uma fila circular básica.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Queue_(abstract_data_type)\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Queue_(abstract_data_type)\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eCom uma fila, o primeiro valor que entra é o primeiro que sai.\n\n ┌──────────────────────────────────────────┐\n┌─────┐ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ ┌─────┐\n│ V06 │ ─▷ │ │ V05 │ ─▷ │ V04 │ ─▷ │ V03 │ ─▷ │ V02 │ │ ─▷ │ V01 │\n└─────┘ | └─────┘ └─────┘ └─────┘ └─────┘ | └─────┘\n └──────────────────────────────────────────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"queue_circular.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a basic circular queue.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tconst items = 5\n\n\tq, err := New(items)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tfor i := 0; i \u003c items; i++ {\n\t\tname := fmt.Sprintf(\"Name%d\", i)\n\t\tif err := q.Enqueue(Data{Name: name}); err != nil {\n\t\t\tfmt.Println(err)\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Println(\"queue:\", name)\n\t}\n\n\tfmt.Println(\"------------------\")\n\n\tf := func(d Data) error {\n\t\tfmt.Println(\"enqueue:\", d.Name)\n\t\treturn nil\n\t}\n\n\tq.Operate(f)\n}\n\n// Data represents what is being stored on the queue.\ntype Data struct {\n\tName string\n}\n\n// Queue represents a list of data.\ntype Queue struct {\n\tCount int\n\tdata []Data\n\tfront int\n\tend int\n}\n\n// New returns a queue with a set capacity.\nfunc New(cap int) (*Queue, error) {\n\tif cap \u003c= 0 {\n\t\treturn nil, errors.New(\"invalid capacity\")\n\t}\n\n\tq := Queue{\n\t\tfront: 0,\n\t\tend: 0,\n\t\tdata: make([]Data, cap),\n\t}\n\treturn \u0026q, nil\n}\n\n// Enqueue inserts data into the queue if there\n// is available capacity.\nfunc (q *Queue) Enqueue(data Data) error {\n\n\t// If the front of the queue is right behind the end or\n\t// if the front is at the end of the capacity and the end\n\t// is at the beginning of the capacity, the queue is full.\n\t// F E - Enqueue (Full) | E F - Enqueue (Full)\n\t// [A][B][C] | [A][B][C]\n\tif q.front+1 == q.end ||\n\t\tq.front == len(q.data) \u0026\u0026 q.end == 0 {\n\t\treturn errors.New(\"queue at capacity\")\n\t}\n\n\tswitch {\n\tcase q.front == len(q.data):\n\n\t\t// If we are at the end of the capacity, then\n\t\t// circle back to the beginning of the capacity by\n\t\t// moving the front pointer to the beginning.\n\t\tq.front = 0\n\t\tq.data[q.front] = data\n\tdefault:\n\n\t\t// Add the data to the current front position\n\t\t// and then move the front pointer.\n\t\tq.data[q.front] = data\n\t\tq.front++\n\t}\n\n\tq.Count++\n\n\treturn nil\n}\n\n// Dequeue removes data into the queue if data exists.\nfunc (q *Queue) Dequeue() (Data, error) {\n\n\t// If the front and end are the same, the\n\t// queue is empty\n\t// EF - (Empty)\n\t// [ ][ ][ ]\n\tif q.front == q.end {\n\t\treturn Data{}, errors.New(\"queue is empty\")\n\t}\n\n\tvar data Data\n\tswitch {\n\tcase q.end == len(q.data):\n\n\t\t// If we are at the end of the capacity, then\n\t\t// circle back to the beginning of the capacity by\n\t\t// moving the end pointer to the beginning.\n\t\tq.end = 0\n\t\tdata = q.data[q.end]\n\tdefault:\n\n\t\t// Remove the data from the current end position\n\t\t// and then move the end pointer.\n\t\tdata = q.data[q.end]\n\t\tq.end++\n\t}\n\n\tq.Count--\n\n\treturn data, nil\n}\n\n// Operate accepts a function that takes data and calls\n// the specified function for every piece of data found.\nfunc (q *Queue) Operate(f func(d Data) error) error {\n\tend := q.end\n\tfor {\n\t\tif end == q.front {\n\t\t\tbreak\n\t\t}\n\n\t\tif end == len(q.data) {\n\t\t\tend = 0\n\t\t}\n\n\t\tif err := f(q.data[end]); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tend++\n\t}\n\treturn nil\n}\n","Hash":"sDoaePCu/Qu1kIe5SImJc9mvXuI="}]},{"Title":"Pilha","Content":"\n \u003ch2\u003ePilha\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este programa de exemplo implementa uma pilha básica.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Stack_(abstract_data_type)\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Stack_(abstract_data_type)\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eCom uma pilha, o primeiro valor que entra é o último que sai.\n\n ┌─────┐\n │ V05 │\n └─────┘\n │\n ▽ ┌─────┐\n ┌───────────┐ ─▷ │ V04 │\n │ ┌─────┐ │ └─────┘\n │ │ V03 │ │\n │ └─────┘ │\n │ ┌─────┐ │\n │ │ V02 │ │\n │ └─────┘ │\n │ ┌─────┐ │\n │ │ V01 │ │\n │ └─────┘ │\n └───────────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"stack.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a basic stack.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tconst items = 5\n\n\tvar s Stack\n\n\tfor i := 0; i \u003c items; i++ {\n\t\tname := fmt.Sprintf(\"Name%d\", i)\n\t\ts.Push(Data{Name: name})\n\n\t\tfmt.Println(\"push:\", name)\n\t}\n\n\tfmt.Println(\"------------------\")\n\n\tf := func(d Data) error {\n\t\tfmt.Println(\"pop:\", d.Name)\n\t\treturn nil\n\t}\n\n\ts.Operate(f)\n}\n\n// Data represents what is being stored on the stack.\ntype Data struct {\n\tName string\n}\n\n// Stack represents a stack of data.\ntype Stack struct {\n\tdata []Data\n}\n\n// Make allows the creation of a stack with an initial\n// capacity for efficiency. Otherwise a stack can be\n// used in its zero value state.\nfunc Make(cap int) *Stack {\n\treturn \u0026Stack{\n\t\tdata: make([]Data, 0, cap),\n\t}\n}\n\n// Count returns the number of items in the stack.\nfunc (s *Stack) Count() int {\n\treturn len(s.data)\n}\n\n// Push adds data into the top of the stack.\nfunc (s *Stack) Push(data Data) {\n\ts.data = append(s.data, data)\n}\n\n// Pop removes data from the top of the stack.\nfunc (s *Stack) Pop() (Data, error) {\n\tif len(s.data) == 0 {\n\t\treturn Data{}, errors.New(\"stack empty\")\n\t}\n\n\t// Calculate the top level index.\n\tidx := len(s.data) - 1\n\n\t// Copy the data from that index position.\n\tdata := s.data[idx]\n\n\t// Remove the top level index from the slice.\n\ts.data = s.data[:idx]\n\n\treturn data, nil\n}\n\n// Peek provides the data stored on the stack based\n// on the level from the bottom. A value of 0 would\n// return the top piece of data.\nfunc (s *Stack) Peek(level int) (Data, error) {\n\tif level \u003c 0 || level \u003e (len(s.data)-1) {\n\t\treturn Data{}, errors.New(\"invalid level position\")\n\t}\n\tidx := (len(s.data) - 1) - level\n\treturn s.data[idx], nil\n}\n\n// Operate accepts a function that takes data and calls\n// the specified function for every piece of data found.\n// It traverses from the top down through the stack.\nfunc (s *Stack) Operate(f func(data Data) error) error {\n\tfor i := len(s.data) - 1; i \u003e -1; i-- {\n\t\tif err := f(s.data[i]); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n","Hash":"yRFX4XWmfL/+gT7mEEJd2qnyUy0="}]},{"Title":"Árvore Binária","Content":"\n \u003ch2\u003eÁrvore Binária\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este programa de exemplo implementa uma árvore binária básica.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Binary_tree\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Binary_tree\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eCom uma árvore binária, os dados são indexados no lado esquerdo\nou direito da árvore. A árvore fica balanceada após cada adição\nde node.\n\n 0 1 2 3 4 5 6 ◁─ Ordem de Inserção\n┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 65 ││ 45 ││ 35 ││ 75 ││ 85 ││ 78 ││ 95 │\n└────┘└────┘└────┘└────┘└────┘└────┘└────┘\n\n ┌────┐\n │ 75 │ ◁─ Árvore Final\n └────┘\n / \\\n ┌────┐ ┌────┐\n │ 45 │ │ 85 │\n └────┘ └────┘\n / \\ / \\\n ┌────┐ ┌────┐ ┌────┐ ┌────┐\n │ 35 │ │ 65 │ │ 78 │ │ 95 │\n └────┘ └────┘ └────┘ └────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"tree_binary.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a basic binary tree.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n)\n\nfunc main() {\n\tvalues := []Data{\n\t\t{Key: 65, Name: \"Bill\"},\n\t\t{Key: 45, Name: \"Ale\"},\n\t\t{Key: 35, Name: \"Joan\"},\n\t\t{Key: 75, Name: \"Hanna\"},\n\t\t{Key: 85, Name: \"John\"},\n\t\t{Key: 78, Name: \"Steph\"},\n\t\t{Key: 95, Name: \"Sally\"},\n\t}\n\n\tvar tree Tree\n\tfor _, value := range values {\n\t\ttree.Insert(value)\n\t}\n\n\tPrettyPrint(tree)\n\tpre := tree.PreOrder()\n\tfmt.Println(\"Pre-order :\", pre)\n\tin := tree.InOrder()\n\tfmt.Println(\"In-order :\", in)\n\tpost := tree.PostOrder()\n\tfmt.Println(\"Post-order:\", post)\n\n\tfmt.Print(\"\\n\")\n\td35, err := tree.Find(35)\n\tif err != nil {\n\t\tfmt.Println(\"ERROR: Unable to find 35\")\n\t\treturn\n\t}\n\tfmt.Println(\"found:\", d35)\n\n\td78, err := tree.Find(78)\n\tif err != nil {\n\t\tfmt.Println(\"ERROR: Unable to find 78\")\n\t\treturn\n\t}\n\tfmt.Println(\"found:\", d78)\n\n\td3, err := tree.Find(3)\n\tif err == nil {\n\t\tfmt.Println(\"ERROR: found 3\", d3)\n\t\treturn\n\t}\n\tfmt.Println(\"not-found: 3\")\n\n\tfmt.Print(\"\\n\")\n\ttree.Delete(75)\n\tPrettyPrint(tree)\n\n\ttree.Delete(85)\n\tPrettyPrint(tree)\n}\n\n// =============================================================================\n\n// Data represents the information being stored.\ntype Data struct {\n\tKey int\n\tName string\n}\n\n// Tree represents all values in the tree.\ntype Tree struct {\n\troot *node\n}\n\n// Insert adds a value into the tree and keeps the tree balanced.\nfunc (t *Tree) Insert(data Data) {\n\tt.root = t.root.insert(t, data)\n\n\tif t.root.balRatio() \u003c -1 || t.root.balRatio() \u003e 1 {\n\t\tt.root = t.root.rebalance()\n\t}\n}\n\n// Find traverses the tree looking for the specified tree.\nfunc (t *Tree) Find(key int) (Data, error) {\n\tif t.root == nil {\n\t\treturn Data{}, errors.New(\"cannot find from an empty tree\")\n\t}\n\n\treturn t.root.find(key)\n}\n\n// Delete removes the key from the tree and keeps it balanced.\nfunc (t *Tree) Delete(key int) error {\n\tif t.root == nil {\n\t\treturn errors.New(\"cannot delete from an empty tree\")\n\t}\n\n\tfakeParent := \u0026node{right: t.root}\n\tif err := t.root.delete(key, fakeParent); err != nil {\n\t\treturn err\n\t}\n\n\tif fakeParent.right == nil {\n\t\tt.root = nil\n\t}\n\treturn nil\n}\n\n// PreOrder traversal get the root node then traversing its child\n// nodes recursively.\n// Use cases: copying tree, mapping prefix notation.\n//\n//\t #1\n//\t / \\\n//\t #2 #5\n//\t / \\ / \\\n//\t#3 #4 #6 #7\nfunc (t *Tree) PreOrder() []Data {\n\torder := []Data{}\n\tf := func(n *node) {\n\t\torder = append(order, n.data)\n\t}\n\tt.root.preOrder(f)\n\treturn order\n}\n\n// InOrder traversal travel from the leftmost node to the rightmost nodes\n// regardless of depth.\n// In-order traversal gives node values in ascending order.\n//\n//\t #4\n//\t / \\\n//\t #2 #6\n//\t / \\ / \\\n//\t#1 #3 #5 #7\nfunc (t *Tree) InOrder() []Data {\n\torder := []Data{}\n\tf := func(n *node) {\n\t\torder = append(order, n.data)\n\t}\n\tt.root.inOrder(f)\n\treturn order\n}\n\n// PostOrder traversal get the leftmost node then its sibling then go up to its\n// parent, recursively.\n// Use cases: tree deletion, mapping postfix notation.\n//\n//\t #7\n//\t / \\\n//\t #3 #6\n//\t / \\ / \\\n//\t#1 #2 #4 #5\nfunc (t *Tree) PostOrder() []Data {\n\torder := []Data{}\n\tf := func(n *node) {\n\t\torder = append(order, n.data)\n\t}\n\tt.root.postOrder(f)\n\treturn order\n}\n\n// =============================================================================\n\n// node represents the data stored in the tree.\ntype node struct {\n\tdata Data\n\tlevel int\n\ttree *Tree\n\tleft *node\n\tright *node\n}\n\n// height returned the level of the tree the node exists in.\n// Level 1 is at the last layer of the tree.\n//\n//\t #7 -- height = 3\n//\t / \\\n//\t #3 #6 -- height = 2\n//\t / \\ / \\\n//\t#1 #2 #4 #5 -- height = 1\nfunc (n *node) height() int {\n\tif n == nil {\n\t\treturn 0\n\t}\n\treturn n.level\n}\n\n// insert adds the node into the tree and makes sure the\n// tree stays balanced.\nfunc (n *node) insert(t *Tree, data Data) *node {\n\tif n == nil {\n\t\treturn \u0026node{data: data, level: 1, tree: t}\n\t}\n\n\tswitch {\n\tcase data.Key \u003c n.data.Key:\n\t\tn.left = n.left.insert(t, data)\n\n\tcase data.Key \u003e n.data.Key:\n\t\tn.right = n.right.insert(t, data)\n\n\tdefault:\n\t\treturn n.rebalance()\n\t}\n\n\tn.level = max(n.left.height(), n.right.height()) + 1\n\treturn n.rebalance()\n}\n\n// find traverses the tree looking for the specified key.\nfunc (n *node) find(key int) (Data, error) {\n\tif n == nil {\n\t\treturn Data{}, errors.New(\"key not found\")\n\t}\n\n\tswitch {\n\tcase n.data.Key == key:\n\t\treturn n.data, nil\n\n\tcase key \u003c n.data.Key:\n\t\treturn n.left.find(key)\n\n\tdefault:\n\t\treturn n.right.find(key)\n\t}\n}\n\n// balRatio provides information about the balance ratio\n// of the node.\nfunc (n *node) balRatio() int {\n\treturn n.right.height() - n.left.height()\n}\n\n// rotateLeft turns the node to the left.\n//\n//\t#3 #4\n//\t \\ / \\\n//\t #4 #3 #5\n//\t \\\n//\t #5\nfunc (n *node) rotateLeft() *node {\n\tr := n.right\n\tn.right = r.left\n\tr.left = n\n\tn.level = max(n.left.height(), n.right.height()) + 1\n\tr.level = max(r.left.height(), r.right.height()) + 1\n\treturn r\n}\n\n// rotateRight turns the node to the right.\n//\n//\t #5 #4\n//\t / / \\\n//\t #4 #3 #5\n//\t /\n//\t#3\nfunc (n *node) rotateRight() *node {\n\tl := n.left\n\tn.left = l.right\n\tl.right = n\n\tn.level = max(n.left.height(), n.right.height()) + 1\n\tl.level = max(l.left.height(), l.right.height()) + 1\n\treturn l\n}\n\n// rotateLeftRight turns the node to the left and then right.\n//\n//\t #5 #5 #4\n//\t / / / \\\n//\t#3 #4 #3 #5\n//\t \\ /\n//\t #4 #3\nfunc (n *node) rotateLeftRight() *node {\n\tn.left = n.left.rotateLeft()\n\tn = n.rotateRight()\n\tn.level = max(n.left.height(), n.right.height()) + 1\n\treturn n\n}\n\n// rotateLeftRight turns the node to the left and then right.\n//\n//\t#3 #3 #4\n//\t \\ \\ / \\\n//\t #5 #4 #3 #5\n//\t / \\\n//\t#4 #5\nfunc (n *node) rotateRightLeft() *node {\n\tn.right = n.right.rotateRight()\n\tn = n.rotateLeft()\n\tn.level = max(n.left.height(), n.right.height()) + 1\n\treturn n\n}\n\n// rebalance will rotate the nodes based on the ratio.\nfunc (n *node) rebalance() *node {\n\tswitch {\n\tcase n.balRatio() \u003c -1 \u0026\u0026 n.left.balRatio() == -1:\n\t\treturn n.rotateRight()\n\n\tcase n.balRatio() \u003e 1 \u0026\u0026 n.right.balRatio() == 1:\n\t\treturn n.rotateLeft()\n\n\tcase n.balRatio() \u003c -1 \u0026\u0026 n.left.balRatio() == 1:\n\t\treturn n.rotateLeftRight()\n\n\tcase n.balRatio() \u003e 1 \u0026\u0026 n.right.balRatio() == -1:\n\t\treturn n.rotateRightLeft()\n\t}\n\treturn n\n}\n\n// findMax finds the maximum element in a (sub-)tree. Its value replaces\n// the value of the to-be-deleted node. Return values: the node itself and\n// its parent node.\nfunc (n *node) findMax(parent *node) (*node, *node) {\n\tswitch {\n\tcase n == nil:\n\t\treturn nil, parent\n\n\tcase n.right == nil:\n\t\treturn n, parent\n\t}\n\treturn n.right.findMax(n)\n}\n\n// replaceNode replaces the parent’s child pointer to n with a pointer\n// to the replacement node. parent must not be nil.\nfunc (n *node) replaceNode(parent, replacement *node) error {\n\tif n == nil {\n\t\treturn errors.New(\"replaceNode() not allowed on a nil node\")\n\t}\n\n\tswitch n {\n\tcase parent.left:\n\t\tparent.left = replacement\n\n\tdefault:\n\t\tparent.right = replacement\n\t}\n\n\treturn nil\n}\n\n// delete removes an element from the tree. It is an error to try\n// deleting an element that does not exist. In order to remove an\n// element properly, Delete needs to know the node’s parent node.\n// Parent must not be nil.\nfunc (n *node) delete(key int, parent *node) error {\n\tif n == nil {\n\t\treturn errors.New(\"value to be deleted does not exist in the tree\")\n\t}\n\n\tswitch {\n\tcase key \u003c n.data.Key:\n\t\treturn n.left.delete(key, n)\n\n\tcase key \u003e n.data.Key:\n\t\treturn n.right.delete(key, n)\n\n\tdefault:\n\t\tswitch {\n\t\tcase n.left == nil \u0026\u0026 n.right == nil:\n\t\t\tn.replaceNode(parent, nil)\n\t\t\treturn nil\n\t\tcase n.left == nil:\n\t\t\tn.replaceNode(parent, n.right)\n\t\t\treturn nil\n\t\tcase n.right == nil:\n\t\t\tn.replaceNode(parent, n.left)\n\t\t\treturn nil\n\t\t}\n\t\treplacement, replParent := n.left.findMax(n)\n\t\tn.data = replacement.data\n\t\treturn replacement.delete(replacement.data.Key, replParent)\n\t}\n}\n\n// preOrder traverses the node by traversing the child nodes recursively.\nfunc (n *node) preOrder(f func(*node)) {\n\tif n != nil {\n\t\tf(n)\n\t\tn.left.preOrder(f)\n\t\tn.right.preOrder(f)\n\t}\n}\n\n// inOrder traversal the node by the leftmost node to the rightmost nodes\n// regardless of depth.\nfunc (n *node) inOrder(f func(*node)) {\n\tif n != nil {\n\t\tn.left.inOrder(f)\n\t\tf(n)\n\t\tn.right.inOrder(f)\n\t}\n}\n\n// postOrder traversal the node by the leftmost node then its sibling\n// then up to its parent, recursively.\nfunc (n *node) postOrder(f func(*node)) {\n\tif n != nil {\n\t\tn.left.postOrder(f)\n\t\tn.right.postOrder(f)\n\t\tf(n)\n\t}\n}\n\n// =============================================================================\n\n// max returns the larger of the two values.\nfunc max(a, b int) int {\n\tif a \u003e b {\n\t\treturn a\n\t}\n\treturn b\n}\n\n// =============================================================================\n\n// PrettyPrint takes a Tree value and displays a pretty print\n// version of the tree.\nfunc PrettyPrint(t Tree) {\n\n\t// Build an index map of positions for print layout.\n\tvalues := make(map[int]int)\n\tmaxIdx := buildIndexMap(values, 0, 0, t.root)\n\n\t// Calculate the total number of levels based on\n\t// the max index provided.\n\tvar levels int\n\tfor {\n\t\tpow := math.Pow(2, float64(levels))\n\t\tif maxIdx \u003c int(pow) {\n\t\t\tbreak\n\t\t}\n\t\tlevels++\n\t}\n\tlevels--\n\n\t// Capture the positional data to use.\n\tdata := generateData(levels)\n\n\t// Set the edge of the top of the tree.\n\tfor sp := 0; sp \u003c data[0].edge; sp++ {\n\t\tfmt.Print(\" \")\n\t}\n\tfmt.Printf(\"%02d\", values[0])\n\tfmt.Print(\"\\n\")\n\n\tdataIdx := 1\n\tfor i := 1; i \u003c len(data); i = i + 2 {\n\n\t\t// Set the edge of this row.\n\t\tfor sp := 0; sp \u003c data[i].edge; sp++ {\n\t\t\tfmt.Print(\" \")\n\t\t}\n\n\t\t// Draw the hashes for this row.\n\t\tdataHashIdx := dataIdx\n\t\tfor h := 0; h \u003c data[i].draw; h++ {\n\t\t\tif values[dataHashIdx] != maxInt {\n\t\t\t\tfmt.Printf(\"/\")\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\" \")\n\t\t\t}\n\t\t\tfor sp := 0; sp \u003c data[i].padding; sp++ {\n\t\t\t\tfmt.Print(\" \")\n\t\t\t}\n\t\t\tif values[dataHashIdx+1] != maxInt {\n\t\t\t\tfmt.Printf(\"\\\\\")\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\" \")\n\t\t\t}\n\t\t\tdataHashIdx += 2\n\n\t\t\tif data[i].gaps != 0 \u0026\u0026 data[i].gaps \u003e h {\n\t\t\t\tfor sp := 0; sp \u003c data[i].gapPad; sp++ {\n\t\t\t\t\tfmt.Print(\" \")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfmt.Print(\"\\n\")\n\n\t\t// Set the edge of the next row.\n\t\tfor sp := 0; sp \u003c data[i+1].edge; sp++ {\n\t\t\tfmt.Print(\" \")\n\t\t}\n\n\t\t// Draw the numbers for this row.\n\t\tfor n := 0; n \u003c data[i+1].draw; n++ {\n\t\t\tif values[dataIdx] != maxInt {\n\t\t\t\tfmt.Printf(\"%02d\", values[dataIdx])\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\" \")\n\t\t\t}\n\t\t\tfor sp := 0; sp \u003c data[i+1].padding; sp++ {\n\t\t\t\tfmt.Print(\" \")\n\t\t\t}\n\t\t\tif values[dataIdx+1] != maxInt {\n\t\t\t\tfmt.Printf(\"%02d\", values[dataIdx+1])\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\" \")\n\t\t\t}\n\t\t\tdataIdx += 2\n\n\t\t\tif data[i+1].gaps != 0 \u0026\u0026 data[i+1].gaps \u003e n {\n\t\t\t\tfor sp := 0; sp \u003c data[i+1].gapPad; sp++ {\n\t\t\t\t\tfmt.Print(\" \")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfmt.Print(\"\\n\")\n\t}\n\n\tfmt.Print(\"\\n\")\n}\n\nconst maxInt = int(^uint(0) \u003e\u003e 1)\n\n// buildIndex traverses the tree and generates a map of index positions\n// for each node in the tree for printing.\n//\n//\t 40\n//\t / \\\n//\t 05 80\n//\t / \\ / \\\n//\t02 25 65 98\n//\n// values{0:40, 1:05, 2:80, 3:02, 4:25, 5:65, 6:98}\nfunc buildIndexMap(values map[int]int, idx int, maxIdx int, n *node) int {\n\n\t// We need to keep track of the highest index position used\n\t// to help calculate tree depth.\n\tif idx \u003e maxIdx {\n\t\tmaxIdx = idx\n\t}\n\n\t// We have reached the end of a branch. Use the maxInt to mark\n\t// no value in that position.\n\tif n == nil {\n\t\tvalues[idx] = maxInt\n\t\treturn maxIdx\n\t}\n\n\t// Save the value of this node in the map at the\n\t// calculated index position.\n\tvalues[idx] = n.data.Key\n\n\t// Check if there are still nodes to check down the left\n\t// branch. When we move down the tree, the next index doubles.\n\tif n.left != nil {\n\t\tnextidx := 2*idx + 1\n\t\tmaxIdx = buildIndexMap(values, nextidx, maxIdx, n.left)\n\t}\n\n\t// Check if there are still nodes to check down the right\n\t// branch. When we move down the tree, the next index doubles.\n\tnextidx := 2*idx + 2\n\tmaxIdx = buildIndexMap(values, nextidx, maxIdx, n.right)\n\n\t// We need to set missing indexes in the map to maxInt.\n\t// So they are ignored in the printing of the map.\n\tif idx == 0 {\n\t\tfor i := 0; i \u003c maxIdx; i++ {\n\t\t\tif _, ok := values[i]; !ok {\n\t\t\t\tvalues[i] = maxInt\n\t\t\t}\n\t\t}\n\t}\n\n\treturn maxIdx\n}\n\n// pos provides positional data for printing a tree.\ntype pos struct {\n\tedge int\n\tdraw int\n\tpadding int\n\tgaps int\n\tgapPad int\n}\n\n// generateData generates all the positional data needed to display\n// nodes at different levels.\nfunc generateData(level int) []pos {\n\ttotalData := (level * 2) - 1\n\tdata := make([]pos, totalData)\n\tedge := 1\n\tdraw := level - 2\n\tpadding := 0\n\tgapPad := 2\n\n\tfor i := totalData - 1; i \u003e= 0; i = i - 2 {\n\n\t\t// Generate starting edge positions.\n\t\tdata[i].edge = int(math.Pow(2, float64(edge)))\n\t\tif i \u003e 0 {\n\t\t\tdata[i-1].edge = data[i].edge + 1\n\t\t}\n\t\tedge++\n\n\t\t// Generate draw information.\n\t\tif draw \u003e 0 {\n\t\t\tdata[i].draw = int(math.Pow(2, float64(draw)))\n\t\t\tdata[i-1].draw = data[i].draw\n\t\t} else {\n\t\t\tdata[i].draw = 1\n\t\t\tif i \u003e 0 {\n\t\t\t\tdata[i-1].draw = 1\n\t\t\t}\n\t\t}\n\t\tdraw--\n\n\t\t// Generate padding information.\n\t\tpadding += data[i].edge\n\t\tdata[i].padding = padding\n\t\tif i \u003e 0 {\n\t\t\tdata[i-1].padding = padding\n\t\t}\n\n\t\t// Generate gaps information.\n\t\tdata[i].gaps = data[i].draw - 1\n\t\tif i \u003e 0 {\n\t\t\tdata[i-1].gaps = data[i].gaps\n\t\t}\n\n\t\t// Generate gap padding information.\n\t\tif i \u003e 2 {\n\t\t\tdata[i-1].gapPad = int(math.Pow(2, float64(gapPad)))\n\t\t\tdata[i].gapPad = data[i-1].gapPad - 2\n\t\t}\n\t\tgapPad++\n\t}\n\n\treturn data\n}\n","Hash":"JAk1zarYonMq48lOOYRWLLVjXms="}]}]} ,"algorithms-fun":{"Title":"Problemas divertidos","Description":"Esta seção contém um conjunto de desafios de código divertidos, que demonstram algumas das capacidades oferecidas pelo Go.","Pages":[{"Title":"Problema do Barbeiro Dorminhoco","Content":"\n \u003ch2\u003eProblema do Barbeiro Dorminhoco\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Este programa de exemplo implementa o problema do barbeiro dorminhoco.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em (Artigo em ingles)\u003ca href=\"https://en.wikipedia.org/wiki/Sleeping_barber_problem\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Sleeping_barber_problem\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Há um barbeiro na barbearia, uma cadeira de barbeiro e \u003ccode\u003en\u003c/code\u003e cadeiras para os clientes em espera. \n\n\n Se não houver clientes, o barbeiro senta-se na cadeira de barbeiro e tira uma soneca. \n\n\n Um cliente que chega deve acordar o barbeiro. Os clientes que chegam subsequentemente ocupam \n\n\n uma cadeira de espera se houver alguma vazia ou vão embora se todas as cadeiras estiverem ocupadas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eSaída:\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eOpening the shop\nBarber ready to work\nCustomer \u0026#34;cust-1\u0026#34; entered shop\nCustomer \u0026#34;cust-1\u0026#34; takes a seat and waits\nBarber servicing customer \u0026#34;cust-1\u0026#34;\nBarber finished customer \u0026#34;cust-1\u0026#34;\nBarber taking a nap\nCustomer \u0026#34;cust-2\u0026#34; entered shop\nCustomer \u0026#34;cust-2\u0026#34; takes a seat and waits\nBarber servicing customer \u0026#34;cust-2\u0026#34;\nCustomer \u0026#34;cust-3\u0026#34; entered shop\nCustomer \u0026#34;cust-3\u0026#34; takes a seat and waits\nBarber finished customer \u0026#34;cust-2\u0026#34;\nBarber servicing customer \u0026#34;cust-3\u0026#34;\nCustomer \u0026#34;cust-4\u0026#34; entered shop\nCustomer \u0026#34;cust-4\u0026#34; takes a seat and waits\nClosing the shop\nBarber finished customer \u0026#34;cust-3\u0026#34;\nBarber servicing customer \u0026#34;cust-4\u0026#34;\nBarber finished customer \u0026#34;cust-4\u0026#34;\nShop closed\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"barber.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to implement the sleeping barber\n// problem.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nfunc main() {\n\tconst maxChairs = 3\n\n\tshop := OpenShop(maxChairs)\n\tdefer shop.Close()\n\n\t// Close the shop in 50 milliseconds.\n\tt := time.NewTimer(50 * time.Millisecond)\n\t\u003c-t.C\n}\n\n// =============================================================================\n\nvar (\n\t// ErrShopClosed is returned when the shop is closed.\n\tErrShopClosed = errors.New(\"shop closed\")\n\n\t// ErrNoChair is returned when all the chairs are occupied.\n\tErrNoChair = errors.New(\"no chair available\")\n)\n\n// customer represents a customer to be serviced.\ntype customer struct {\n\tname string\n}\n\n// Shop represents the barber's shop which contains chairs for customers\n// that customers can occupy and the barber can service. The shop can\n// be closed for business.\ntype Shop struct {\n\topen int32 // Determines if the shop is open for business.\n\tchairs chan customer // The set of chairs customers wait in.\n\twgClose sync.WaitGroup // Provides support for closing the shop.\n}\n\n// OpenShop creates a new shop for business and gets the barber working.\nfunc OpenShop(maxChairs int) *Shop {\n\tfmt.Println(\"Opening the shop\")\n\n\ts := Shop{\n\t\tchairs: make(chan customer, maxChairs),\n\t}\n\tatomic.StoreInt32(\u0026s.open, 1)\n\n\t// This is the barber and they will service customers.\n\n\ts.wgClose.Add(1)\n\tgo func() {\n\t\tdefer s.wgClose.Done()\n\n\t\tfmt.Println(\"Barber ready to work\")\n\n\t\tfor cust := range s.chairs {\n\t\t\ts.serviceCustomer(cust)\n\t\t}\n\t}()\n\n\t// Start creating customers who enter the shop.\n\n\tgo func() {\n\t\tvar id int64\n\n\t\tfor {\n\t\t\t// Wait some random time for the next customer to enter.\n\t\t\ttime.Sleep(time.Duration(rand.Intn(75)) * time.Millisecond)\n\n\t\t\tname := fmt.Sprintf(\"cust-%d\", atomic.AddInt64(\u0026id, 1))\n\t\t\tif err := s.newCustomer(name); err != nil {\n\t\t\t\tif err == ErrShopClosed {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn \u0026s\n}\n\n// Close prevents any new customers from entering the shop and waits for\n// the barber to finish all existing customers.\nfunc (s *Shop) Close() {\n\tfmt.Println(\"Closing the shop\")\n\tdefer fmt.Println(\"Shop closed\")\n\n\t// Mark the shop closed.\n\tatomic.StoreInt32(\u0026s.open, 0)\n\n\t// Wait for the barber to finish with the existing customers.\n\tclose(s.chairs)\n\ts.wgClose.Wait()\n}\n\n// =============================================================================\n\nfunc (s *Shop) serviceCustomer(cust customer) {\n\tfmt.Printf(\"Barber servicing customer %q\\n\", cust.name)\n\n\ttime.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)\n\n\tfmt.Printf(\"Barber finished customer %q\\n\", cust.name)\n\n\tif len(s.chairs) == 0 \u0026\u0026 atomic.LoadInt32(\u0026s.open) == 1 {\n\t\tfmt.Println(\"Barber taking a nap\")\n\t}\n}\n\nfunc (s *Shop) newCustomer(name string) error {\n\tif atomic.LoadInt32(\u0026s.open) == 0 {\n\t\tfmt.Printf(\"Customer %q leaves, shop closed\\n\", name)\n\t\treturn ErrShopClosed\n\t}\n\n\tfmt.Printf(\"Customer %q entered shop\\n\", name)\n\n\tselect {\n\tcase s.chairs \u003c- customer{name: name}:\n\t\tfmt.Printf(\"Customer %q takes a seat and waits\\n\", name)\n\n\tdefault:\n\t\tfmt.Printf(\"Customer %q leaves, no seat\\n\", name)\n\t}\n\n\treturn nil\n}\n","Hash":"sK2TtWvYjjkEtc7R98KOX1+/1eY="}]},{"Title":"Frequência","Content":"\n \u003ch2\u003eFrequência\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este programa de exemplo mostra como implementar uma função que pode encontrar \n\n\n a frequência de um rune específico que é utilizado em uma frase especificada.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eSequencial: Um algoritmo linear para realizar a contagem de rune.\u003c/li\u003e\n \n \u003cli\u003eConcorrente: Um algoritmo concorrente para realizar a contagem de rune.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"freq_sequential.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to implement a function that can\n// find the frequency a given rune is used in a specified sentence.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tsentence := `The quick brown fox jumps over the lazy dog Stay hungry.\n\tStay foolish Keep going. Be all in Boldness be my friend Screw it,\n\tlet's do it My life is my message Leave no stone unturned Dream big.\n\tPray bigger`\n\n\tprint(sequential(sentence))\n}\n\nfunc sequential(text string) map[rune]int {\n\tm := make(map[rune]int)\n\n\tfor _, r := range text {\n\t\tm[r]++\n\t}\n\n\treturn m\n}\n\nfunc print(m map[rune]int) {\n\tvar cols int\n\n\tfor r := 65; r \u003c 65+26; r++ {\n\t\tv := m[rune(r)]\n\t\tfmt.Printf(\"%q:%d, \", rune(r), v)\n\n\t\tv = m[rune(r+32)]\n\t\tfmt.Printf(\"%q:%d, \", rune(r+32), v)\n\n\t\tcols++\n\t\tif cols == 5 {\n\t\t\tfmt.Print(\"\\n\")\n\t\t\tcols = 0\n\t\t}\n\t}\n}\n","Hash":"NMpux3E8w78VCZ0C8rWqbN9Jgnw="},{"Name":"freq_concurrent.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample concurrent program shows you how to implement a function\n// that can find the frequency a given rune is used in a specified sentence.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n)\n\nfunc main() {\n\tsentence := `The quick brown fox jumps over the lazy dog Stay hungry.\n\tStay foolish Keep going. Be all in Boldness be my friend Screw it,\n\tlet's do it My life is my message Leave no stone unturned Dream big.\n\tPray bigger`\n\n\tprint(concurrent(sentence))\n}\n\nfunc concurrent(text string) map[rune]int {\n\tm := make(map[rune]int) // Map with final result\n\tg := runtime.GOMAXPROCS(0) // Number of goroutines\n\tl := len(text) // Number of bytes to process\n\tb := l / g // Number of buckets, one per goroutine\n\n\t// Receives the result of each bucket processed\n\t// by a goroutine.\n\tch := make(chan map[rune]int, g)\n\n\t// Create g number of goroutines.\n\n\tfor i := 0; i \u003c g; i++ {\n\t\tstr := i * b // Starting idx position of bucket\n\t\tend := str + b // Ending idx position of bucket\n\t\tif i == g-1 { // The last bucket gets ant remaining bytes\n\t\t\tend = end + (l - end)\n\t\t}\n\n\t\tgo func() {\n\t\t\tm := make(map[rune]int)\n\n\t\t\tdefer func() {\n\t\t\t\tch \u003c- m\n\t\t\t}()\n\n\t\t\t// This G processes its bucket sequentially.\n\t\t\tfor _, r := range text[str:end] {\n\t\t\t\tm[r]++\n\t\t\t}\n\t\t}()\n\t}\n\n\t// Wait for the results of each bucket to come\n\t// in and process them into the final map.\n\n\tfor i := 0; i \u003c g; i++ {\n\t\tresult := \u003c-ch\n\t\tfor rk, rv := range result {\n\t\t\tm[rk] = m[rk] + rv\n\t\t}\n\t}\n\n\treturn m\n}\n\nfunc print(m map[rune]int) {\n\tvar cols int\n\n\tfor r := 65; r \u003c 65+26; r++ {\n\t\tv := m[rune(r)]\n\t\tfmt.Printf(\"%q:%d, \", rune(r), v)\n\n\t\tv = m[rune(r+32)]\n\t\tfmt.Printf(\"%q:%d, \", rune(r+32), v)\n\n\t\tcols++\n\t\tif cols == 5 {\n\t\t\tfmt.Print(\"\\n\")\n\t\t\tcols = 0\n\t\t}\n\t}\n}\n","Hash":"UpS5seVg/m0LGLojYuxI8wtnuIU="}]},{"Title":"Codificação/Decodificação de Quantidade de Comprimento Variável","Content":"\n \u003ch2\u003eCodificação/Decodificação de Quantidade de Comprimento Variável\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este programa de exemplo demonstra como Go pode ser usado para implementar codificação/decodificação de quantidade de comprimento variável.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em (Artigo em inglês) \u003ca href=\"https://en.wikipedia.org/wiki/Variable-length_code\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Variable-length_code\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Em resumo, o objetivo desta codificação é salvar valores inteiros de uma forma que economize bytes. \n\n\n Apenas os primeiros 7 bits de cada byte são significativos (alinhados à direita; algo como um byte ASCII). \n\n\n Então, se você tem um valor de 32 bits, você precisa desempacotar-lo em uma série de bytes de 7 bits. \n\n\n Claro, você terá um número variável de bytes dependendo do seu inteiro. Para indicar qual é o último byte da série, \n\n\n você deixa o bit #7 livre. Em todos os bytes precedentes, você define o bit #7.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Então, se um inteiro está entre 0-127, ele pode ser representado como um byte. O maior inteiro permitido é 0FFFFFFF, \n\n\n que se traduz em 4 bytes de comprimento variável. \n\n\n Aqui estão exemplos de tempos delta como valores de 32 bits, e as quantidades de comprimento variável nas quais eles se traduzem:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eNUMERO QUANTIDADE VARIÁVEL\n00000000 00\n00000040 40\n0000007F 7F\n00000080 81 00\n00002000 C0 00\n00003FFF FF 7F\n00004000 81 80 00\n00100000 C0 80 00\n001FFFFF FF FF 7F\n00200000 81 80 80 00\n08000000 C0 80 80 00\n0FFFFFFF FF FF FF 7F\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Uma quantidade de comprimento variável (VLQ) é um código universal que utiliza um número arbitrário de octetos binários (bytes de oito bits) \n\n\n para representar um inteiro arbitrariamente grande. Foi definido para uso no formato padrão de arquivo MIDI[1] para economizar espaço adicional \n\n\n para um sistema com recursos limitados, e também é usado no posterior Formato Musical Extensível (XMF). Um VLQ é essencialmente uma representação \n\n\n base-128 de um inteiro sem sinal, com a adição do oitavo bit para marcar a continuação de bytes. Veja o exemplo abaixo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eInt: 16384\nIntHex: 0x00004000\nIntBin: 00000000 00000000 01000000 00000000\nVLQHex: 0x81 0x80 0x00\nVLQBin: 00000000 10000001 10000000 00000000\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Vamos supor que eu queira representar o número 3435 em VLQ. 3435 em binário é 110101101011. \n\n\n Não podemos encaixar isso em um byte. Então, vamos dividi-lo a partir do final em blocos de 7 bits.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eSepteto 7 6 5 4 3 2 1\n#1 1 1 0 1 0 1 1\n#2 0 0 1 1 0 1 0\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Agora, nós prefixamos todos, exceto o último, com um bit 1 para indicar que um octeto segue e prefixamos \n\n\n um bit 0 ao último, sinalizando o octeto final.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eOcteto 8 7 6 5 4 3 2 1\n#1 0 1 1 0 1 0 1 1\n#2 1 0 0 1 1 0 1 0\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Finalmente, nós os concatenamos, o octeto mais significativo primeiro, em\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Codificado: 10011010 01101011 ToHex: 0x9A 0x6B\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eRecursos\u003c/b\u003e \u003cb\u003eExtra:\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Variable-length_quantity\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Variable-length_quantity\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blogs.infosupport.com/a-primer-on-vlq/\" target=\"_blank\"\u003ehttps://blogs.infosupport.com/a-primer-on-vlq/\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003ePara\u003c/b\u003e \u003cb\u003euma\u003c/b\u003e \u003cb\u003eexcelente\u003c/b\u003e \u003cb\u003eimplementação\u003c/b\u003e \u003cb\u003edesse\u003c/b\u003e \u003cb\u003ealgoritmo\u003c/b\u003e \u003cb\u003eveja\u003c/b\u003e \u003cb\u003eaqui:\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/go-audio/midi/blob/master/varint.go\" target=\"_blank\"\u003ehttps://github.com/go-audio/midi/blob/master/varint.go\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"vlq.go","Content":"package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/bits\"\n)\n\nfunc main() {\n\tinputs := [][]byte{\n\t\t[]byte{0x7F},\n\t\t[]byte{0x81, 0x00},\n\t\t[]byte{0xC0, 0x00},\n\t\t[]byte{0xFF, 0x7F},\n\t\t[]byte{0x81, 0x80, 0x00},\n\t\t[]byte{0xFF, 0xFF, 0x7F},\n\t\t[]byte{0x81, 0x80, 0x80, 0x00},\n\t\t[]byte{0xC0, 0x80, 0x80, 0x00},\n\t\t[]byte{0xFF, 0xFF, 0xFF, 0x7F},\n\t\t[]byte{0x82, 0x00},\n\t\t[]byte{0x81, 0x10},\n\t}\n\n\tfor _, input := range inputs {\n\t\tdecoded, err := DecodeVarint(input)\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\treturn\n\t\t}\n\n\t\tencoded := EncodeVarint(decoded)\n\t\tfmt.Printf(\"input 0x%x, decoded: %d, encoded: 0x%x\\n\", input, decoded, encoded)\n\t}\n}\n\n// DecodeVarint takes a variable length VLQ based integer and\n// decodes it into a 32 bit integer.\nfunc DecodeVarint(input []byte) (uint32, error) {\n\tconst lastBitSet = 0x80 // 1000 0000\n\n\tvar d uint32\n\tvar bitPos int\n\n\tfor i := len(input) - 1; i \u003e= 0; i-- {\n\t\tn := uint8(input[i])\n\n\t\t// Process the first 7 bits and ignore the 8th.\n\t\tfor checkBit := 0; checkBit \u003c 7; checkBit++ {\n\n\t\t\t// Rotate the last bit off and move it to the back.\n\t\t\t// Before: 0000 0001\n\t\t\t// After: 1000 0000\n\t\t\tn = bits.RotateLeft8(n, -1)\n\n\t\t\t// Calculate based on only those 1 bits that were rotated.\n\t\t\t// Convert the bitPos to base 10.\n\t\t\tif n \u003e= lastBitSet {\n\t\t\t\tswitch {\n\t\t\t\tcase bitPos == 0:\n\t\t\t\t\td++\n\t\t\t\tdefault:\n\t\t\t\t\tbase10 := math.Pow(2, float64(bitPos))\n\t\t\t\t\td += uint32(base10)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Move the bit position.\n\t\t\tbitPos++\n\t\t}\n\t}\n\n\treturn d, nil\n}\n\n// EncodeVarint takes a 32 bit integer and encodes it into\n// a variable length VLQ based integer.\nfunc EncodeVarint(n uint32) []byte {\n\tconst maxBytes = 4\n\tconst eightBitSet = 0x80 // 1000 0000\n\tconst lastBitSet = 0x80000000 // 1000 0000 0000 0000\n\n\tencoded := make([]byte, maxBytes)\n\n\tfor bytePos := maxBytes - 1; bytePos \u003e= 0; bytePos-- {\n\t\tvar d uint8\n\n\t\t// Process the next 7 bits.\n\t\tfor checkBit := 0; checkBit \u003c 7; checkBit++ {\n\n\t\t\t// Rotate the last bit off and move it to the back.\n\t\t\t// Before: 0000 0000 0000 0001\n\t\t\t// After: 1000 0000 0000 0000\n\t\t\tn = bits.RotateLeft32(n, -1)\n\n\t\t\t// Calculate based on only those 1 bits that were\n\t\t\t// rotated. Convert the bit position to base 10.\n\t\t\tif n \u003e= lastBitSet {\n\t\t\t\tswitch {\n\t\t\t\tcase checkBit == 0:\n\t\t\t\t\td++\n\t\t\t\tdefault:\n\t\t\t\t\tbase10 := math.Pow(2, float64(checkBit))\n\t\t\t\t\td += uint8(base10)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// These values need the 8th bit to be set as 1.\n\t\tif bytePos \u003c 3 {\n\t\t\td += eightBitSet\n\t\t}\n\n\t\t// Store the value in reserve order.\n\t\tencoded[bytePos] = d\n\t}\n\n\t// Remove leading zero values by finding values that only\n\t// have their eight bit set.\n\tfor bytePos, b := range encoded {\n\t\tif b == eightBitSet {\n\t\t\tcontinue\n\t\t}\n\t\tencoded = encoded[bytePos:]\n\t\tbreak\n\t}\n\n\treturn encoded\n}\n","Hash":"pS5A986ELRif8kf7WHEzL/Wpo4M="}]}]} ,"algorithms-slices":{"Title":"Operações com Slice","Description":"Esta seção fornece exemplos que realizam operações em slice.","Pages":[{"Title":"Número Mínimo","Content":"\n \u003ch2\u003eNúmero Mínimo\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O programa de exemplo implementa uma função para obter o integer mínimo de um slice de integer.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eDiagram\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e┌────┐┌────┐┌────┐\n│ 10 ││ 30 ││ 15 │ ────▷ 10\n└────┘└────┘└────┘\n\n┌────┐\n│ 25 │ ────▷ 25\n└────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"min_number.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to retrieve the minimum integer\n// from a slice of integers.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ttt := []struct {\n\t\tinput []int\n\t\texpected int\n\t}{\n\t\t{[]int{}, 0},\n\t\t{nil, 0},\n\t\t{[]int{10}, 10},\n\t\t{[]int{20, 30, 10, 50}, 10},\n\t\t{[]int{30, 50, 10}, 10},\n\t}\n\n\tfor _, test := range tt {\n\t\tvalue, err := Min(test.input)\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Printf(\"Input: %d, Value: %d, Expected: %d, Match: %v\\n\",\n\t\t\ttest.input,\n\t\t\tvalue,\n\t\t\ttest.expected,\n\t\t\tvalue == test.expected,\n\t\t)\n\t}\n}\n\n// Min returns the minimum integer in the slice.\nfunc Min(n []int) (int, error) {\n\n\t// First check there are numbers in the collection.\n\tif len(n) == 0 {\n\t\treturn 0, fmt.Errorf(\"slice %#v has no elements\", n)\n\t}\n\n\t// If the length of the slice is 1 then return the\n\t// integer at index 0.\n\tif len(n) == 1 {\n\t\treturn n[0], nil\n\t}\n\n\t// Save the first value as current min and then loop over\n\t// the slice of integers looking for a smaller number.\n\tmin := n[0]\n\tfor _, num := range n[1:] {\n\n\t\t// If num is less than min. Assign min to num.\n\t\tif num \u003c min {\n\t\t\tmin = num\n\t\t}\n\t}\n\n\treturn min, nil\n}\n","Hash":"OBzcPivErh/fh3wPr1IwdFhgSCQ="}]},{"Title":"Número Máximo","Content":"\n \u003ch2\u003eNúmero Máximo\u003c/h2\u003e\n \n \n \u003cp\u003e\n O programa de exemplo implementa uma função para obter o integer máximo de um slice de integer.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e┌────┐┌────┐┌────┐\n│ 45 ││ 23 ││ 68 │ ────▷ 68\n└────┘└────┘└────┘\n\n┌────┐\n│ 78 │ ────▷ 78\n└────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"max_number.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to retrieve the maximum integer\n// from a slice of integers.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ttt := []struct {\n\t\tinput []int\n\t\texpected int\n\t}{\n\t\t{[]int{}, 0},\n\t\t{nil, 0},\n\t\t{[]int{10}, 10},\n\t\t{[]int{20, 30, 10, 50}, 50},\n\t\t{[]int{30, 50, 10}, 50},\n\t}\n\n\tfor _, test := range tt {\n\t\tvalue, err := Max(test.input)\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Printf(\"Input: %d, Value: %d, Expected: %d, Match: %v\\n\",\n\t\t\ttest.input,\n\t\t\tvalue,\n\t\t\ttest.expected,\n\t\t\tvalue == test.expected,\n\t\t)\n\t}\n}\n\n// Max returns the maximum integer in the slice.\nfunc Max(n []int) (int, error) {\n\n\t// First check there are numbers in the collection.\n\tif len(n) == 0 {\n\t\treturn 0, fmt.Errorf(\"slice %#v has no elements\", n)\n\t}\n\n\t// If the length of the slice is 1 then return the\n\t// integer at index 0.\n\tif len(n) == 1 {\n\t\treturn n[0], nil\n\t}\n\n\t// Save the first value as current max and then loop over\n\t// the slice of integers looking for a larger number.\n\tmax := n[0]\n\tfor _, num := range n[1:] {\n\n\t\t// If num is greater than max, assign max to num.\n\t\tif num \u003e max {\n\t\t\tmax = num\n\t\t}\n\t}\n\n\treturn max, nil\n}\n","Hash":"A05aPTEmS8hEsGYiYmQ3zVkupXs="}]}]} ,"constants":{"Title":"Constantes","Description":"Uma característica distintiva da linguagem Go é como a linguagem implementa constantes.","Pages":[{"Title":"Constantes","Content":"\n \u003ch2\u003eConstantes\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Uma das características mais singulares de Go é a forma como a linguagem implementa constantes.\n\n\n As regras para constantes na especificação da linguagem são exclusivas para Go. Elas oferecem\n\n\n a flexibilidade que Go precisa para tornar o código que escrevemos legível e intuitivo, enquanto ainda\n\n\n mantém a segurança de tipo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Constantes podem ser tipadas ou não tipadas. Quando uma constante é não tipada, ela é considerada\n\n\n de um certo \u0026#34;kind\u0026#34; (Tipo/Categoria específica em go). Constantes desse \u0026#34;kind\u0026#34; podem ser convertidas implicitamente pelo compilador. \n\n\n Isso tudo acontece em tempo de compilação e não em tempo de execução.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declare e inicialize constantes\t\t\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Sistema de tipos paralelo (Kind) (faltando)\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e iota\t\t\t\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Conversão implícita\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n \n \u003cpre class=\"codeblock\"\u003econst ui = 12345 // \u0026#34;kind\u0026#34;: int\nconst uf = 3.141592 // \u0026#34;kind\u0026#34;: Floating point\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Constantes numéricas não tipadas têm uma precisão de 256 bits, conforme especificado pela especificação.\n\n\n Elas são baseadas em um \u0026#34;kind\u0026#34; \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst ti int = 12345 // tipo: int\nconst tf float64 = 3.141592 // tipo: float64\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Constantes tipadas ainda usam o sistema de tipo de constante, mas sua precisão é restrita.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst myUint8 uint8 = 1000 // Erro de compilação: constant 1000 overflows uint8\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Isso não funciona porque o número 1000 é grande demais para ser armazenado em um uint8\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar answer = 3 * 0.333 // float64 = KindFloat(3) * KindFloat(0.333)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A aritmética de constantes suporta o uso de diferentes \u0026#34;kinds\u0026#34; de constantes. A Promoção de Tipo (em inglês \u0026#34;Kind Promotion\u0026#34;)\n\n\n é usada para lidar com esses diferentes cenários. Tudo isso acontece implicitamente. A variável \u0026#34;answer\u0026#34;\n\n\n neste exemplo será do tipo float64 e representará 0.999 com uma precisão de 64 bits.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst third = 1 / 3.0 // KindFloat = KindFloat(1) / KindFloat(3.0)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A terceira constante será do tipo float e representará 1/3 com uma precisão de 256 bits.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst zero = 1 / 3 // KindInt = KindInt(1) / KindInt(3)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A constante \u0026#34;zero\u0026#34; será do \u0026#34;kind\u0026#34; inteiro e definida como 0, pois a divisão de inteiros não tem resto.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst one int8 = 1\nconst two = 2 * one // int8(2) * int8(1)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este é um exemplo de aritmética de constantes entre constantes tipadas e não tipadas.\n\n\n Neste caso, uma constante de um tipo tem precedência sobre uma constante de um \u0026#34;kind\u0026#34;. \n\n\n As duas constantes serão do tipo int8 e definidas como 2 \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst maxInt = 9223372036854775807\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este é o valor máximo para um inteiro de 64 bits.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst bigger = 9223372036854775808543522345\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A constante \u0026#34;bigger\u0026#34; tem um valor muito maior do que um inteiro de 64 bits, mas pode ser\n\n\n armazenada em uma constante do \u0026#34;kind\u0026#34; int, uma vez que constantes do \u0026#34;kind\u0026#34; int não estão limitadas a\n\n\n 64 bits de precisão.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst bigger int64 = 9223372036854775808543522345\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Erro de compilação:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econstant 9223372036854775808543522345 overflows int64\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n No entanto, se bigger fosse uma constante do tipo int64, isso não compilaria.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eIOTA\u003c/h2\u003e\n \n \n \u003cp\u003e\n IOTA fornece suporte para definir constantes inteiras sucessivas. É possível que\n\n\n o nome venha da função inteira ⍳ da linguagem de programação APL. No APL,\n\n\n a função ⍳ (representada pela nona letra do alfabeto grego, iota) é\n\n\n usada para criar um array baseado em zero de inteiros consecutivos e ascendentes de um comprimento\n\n\n especificado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst (\n A1 = iota // 0 : Começa em 0\n B1 = iota // 1 : Incrementado em 1\n C1 = iota // 2 : Incrementado em 1\n)\nfmt.Println(A1, B1, C1)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e0 1 2\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A palavra-chave iota funciona dentro de um bloco de constantes e começa com o valor de 0. Então,\n\n\n para cada constante sucessiva declarada no bloco, iota é incrementada em 1.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst (\n A2 = iota // 0 : Começa em 0\n B2 // 1 : Incrementado em 1\n C2 // 2 : Incrementado em 1\n)\nfmt.Println(A2, B2, C2)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e0 1 2\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você não precisa repetir o uso da palavra-chave iota. A natureza sucessiva das\n\n\n constantes inteiras é assumida uma vez aplicada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst (\n A3 = iota \u0026#43; 1 // 1 : 0 \u0026#43; 1\n B3 // 2 : 1 \u0026#43; 1\n C3 // 3 : 2 \u0026#43; 1\n)\nfmt.Println(A3, B3, C3)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e1 2 3\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Se você não quiser aplicar um padrão matemático, pode realizar alguns cálculos e\n\n\n a matemática é reaplicada com um valor crescente de iota.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003econst (\n Ldate= 1 \u0026lt;\u0026lt; iota // 1 : Desloque 1 para a esquerda 0. 0000 0001\n Ltime // 2 : Desloque 1 para a esquerda 1. 0000 0010\n Lmicroseconds // 4 : Desloque 1 para a esquerda 2. 0000 0100\n Llongfile // 8 : Desloque 1 para a esquerda 3. 0000 1000\n Lshortfile // 16 : Desloque 1 para a esquerda 4. 0001 0000\n LUTC // 32 : Desloque 1 para a esquerda 5. 0010 0000\n)\n\nfmt.Println(Ldate, Ltime, Lmicroseconds, Llongfile, Lshortfile, LUTC)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e1 2 4 8 16 32\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode usar esse recurso como o pacote Log faz para definir flags. Neste caso, operações de bit\n\n\n são aplicadas com valores crescentes de iota para calcular os valores das flags.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eConstantes não são variáveis.\u003c/li\u003e\n \n \u003cli\u003eEles existem apenas durante a compilação.\u003c/li\u003e\n \n \u003cli\u003eConstantes não tipadas podem ser convertidas implicitamente onde constantes tipadas e variáveis não podem.\u003c/li\u003e\n \n \u003cli\u003ePense em constantes não tipadas como tendo um \u0026#34;Kind\u0026#34; (Espécie), não um \u0026#34;Type\u0026#34; (Tipo).\u003c/li\u003e\n \n \u003cli\u003eAprenda sobre conversões explícitas e implícitas.\u003c/li\u003e\n \n \u003cli\u003eVeja o poder das constantes e seu uso na biblioteca padrão.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeituras extras\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/ref/spec#Constants\" target=\"_blank\"\u003eConstants specification\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/constants\" target=\"_blank\"\u003eConstants\u003c/a\u003e - Rob Pike \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/04/introduction-to-numeric-constants-in-go.html\" target=\"_blank\"\u003eIntroduction To Numeric Constants In Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare constants and their\n// implementation in Go.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Constants live within the compiler.\n\t// They have a parallel type system.\n\t// Compiler can perform implicit conversions of untyped constants.\n\n\t// Untyped Constants.\n\tconst ui = 12345 // kind: integer\n\tconst uf = 3.141592 // kind: floating-point\n\n\t// Typed Constants still use the constant type system but their precision\n\t// is restricted.\n\tconst ti int = 12345 // type: int\n\tconst tf float64 = 3.141592 // type: float64\n\n\t// ./constants.go:XX: constant 1000 overflows uint8\n\t// const myUint8 uint8 = 1000\n\n\t// Constant arithmetic supports different kinds.\n\t// Kind Promotion is used to determine kind in these scenarios.\n\n\t// Variable answer will of type float64.\n\tvar answer = 3 * 0.333 // KindFloat(3) * KindFloat(0.333)\n\tfmt.Println(answer)\n\n\t// Constant third will be of kind floating point.\n\tconst third = 1 / 3.0 // KindFloat(1) / KindFloat(3.0)\n\tfmt.Println(third)\n\n\t// Constant zero will be of kind integer.\n\tconst zero = 1 / 3 // KindInt(1) / KindInt(3)\n\tfmt.Println(zero)\n\n\t// This is an example of constant arithmetic between typed and\n\t// untyped constants. Must have like types to perform math.\n\tconst one int8 = 1\n\tconst two = 2 * one // int8(2) * int8(1)\n\tfmt.Println(two)\n}\n","Hash":"N6BHVINKTeEG8qSHYJENmy/QyVc="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how constants do have a parallel type system.\npackage main\n\nimport \"fmt\"\n\nconst (\n\t// Max integer value on 64 bit architecture.\n\tmaxInt = 9223372036854775807\n\n\t// Much larger value than int64.\n\tbigger = 9223372036854775808543522345\n\n\t// Will NOT compile\n\t// biggerInt int64 = 9223372036854775808543522345\n)\n\nfunc main() {\n\tfmt.Println(\"Will Compile\")\n}\n","Hash":"xwdJNm1b7a9ykruakvMsW5PkERQ="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how iota works.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\tconst (\n\t\tA1 = iota // 0 : Start at 0\n\t\tB1 = iota // 1 : Increment by 1\n\t\tC1 = iota // 2 : Increment by 1\n\t)\n\n\tfmt.Println(\"1:\", A1, B1, C1)\n\n\tconst (\n\t\tA2 = iota // 0 : Start at 0\n\t\tB2 // 1 : Increment by 1\n\t\tC2 // 2 : Increment by 1\n\t)\n\n\tfmt.Println(\"2:\", A2, B2, C2)\n\n\tconst (\n\t\tA3 = iota + 1 // 1 : Start at 0 + 1\n\t\tB3 // 2 : Increment by 1\n\t\tC3 // 3 : Increment by 1\n\t)\n\n\tfmt.Println(\"3:\", A3, B3, C3)\n\n\tconst (\n\t\tLdate = 1 \u003c\u003c iota // 1 : Shift 1 to the left 0. 0000 0001\n\t\tLtime // 2 : Shift 1 to the left 1. 0000 0010\n\t\tLmicroseconds // 4 : Shift 1 to the left 2. 0000 0100\n\t\tLlongfile // 8 : Shift 1 to the left 3. 0000 1000\n\t\tLshortfile // 16 : Shift 1 to the left 4. 0001 0000\n\t\tLUTC // 32 : Shift 1 to the left 5. 0010 0000\n\t)\n\n\tfmt.Println(\"Log:\", Ldate, Ltime, Lmicroseconds, Llongfile, Lshortfile, LUTC)\n}\n","Hash":"9BjwMctAu4zOmYCkZIYCjh7LiBg="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n/*\n// A Duration represents the elapsed time between two instants as\n// an int64 nanosecond count. The representation limits the largest\n// representable duration to approximately 290 years.\n\ntype Duration int64\n\n// Common durations. There is no definition for units of Day or larger\n// to avoid confusion across daylight savings time zone transitions.\n\nconst (\n Nanosecond Duration = 1\n Microsecond = 1000 * Nanosecond\n Millisecond = 1000 * Microsecond\n Second = 1000 * Millisecond\n Minute = 60 * Second\n Hour = 60 * Minute\n)\n\n// Add returns the time t+d.\nfunc (t Time) Add(d Duration) Time\n*/\n\n// Sample program to show how literal, constant and variables work\n// within the scope of implicit conversion.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\n\t// Use the time package to get the current date/time.\n\tnow := time.Now()\n\n\t// Subtract 5 nanoseconds from now using a literal constant.\n\tliteral := now.Add(-5)\n\n\t// Subtract 5 seconds from now using a declared constant.\n\tconst timeout = 5 * time.Second // time.Duration(5) * time.Duration(1000000000)\n\tconstant := now.Add(-timeout)\n\n\t// Subtract 5 nanoseconds from now using a variable of type int64.\n\tminusFive := int64(-5)\n\tvariable := now.Add(minusFive)\n\n\t// example4.go:50: cannot use minusFive (type int64) as type time.Duration in argument to now.Add\n\n\t// Display the values.\n\tfmt.Printf(\"Now : %v\\n\", now)\n\tfmt.Printf(\"Literal : %v\\n\", literal)\n\tfmt.Printf(\"Constant: %v\\n\", constant)\n\tfmt.Printf(\"Variable: %v\\n\", variable)\n}\n","Hash":"ZoSxgPKX92UME2fMkcUOCuRmyIQ="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Declare uma constante não tipada e uma tipada e exiba seus valores.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Divida duas constantes literais em uma variável tipada e exiba o valor.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare an untyped and typed constant and display their values.\n//\n// Multiply two literal constants into a typed variable and display the value.\npackage main\n\n// Add imports.\n\nconst (\n// Declare a constant named server of kind string and assign a value.\n\n// Declare a constant named port of type integer and assign a value.\n)\n\nfunc main() {\n\n\t// Display the value of both server and port.\n\n\t// Divide a constant of kind integer and kind floating point and\n\t// assign the result to a variable.\n\n\t// Display the value of the variable.\n}\n","Hash":"jVS9BSi87w993JvmHUeIavJGIgU="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare an untyped and typed constant and display their values.\n//\n// Multiply two literal constants into a typed variable and display the value.\npackage main\n\nimport \"fmt\"\n\nconst (\n\t// server is the IP address for connecting.\n\tserver = \"124.53.24.123\"\n\n\t// port is the port to make that connection.\n\tport int16 = 9000\n)\n\nfunc main() {\n\n\t// Display the server information.\n\tfmt.Println(server)\n\tfmt.Println(port)\n\n\t// Calculate the number of minutes in 5320 seconds.\n\tminutes := 5320 / 60.0\n\tfmt.Println(minutes)\n}\n","Hash":"jMTAOpRhUCTuuH/d7d5mxVc5wh4="}]}]} ,"generics-channels":{"Title":"Channels","Description":"Explore como a equipe do Go poderia adicionar um pacote de padrões de concorrência à biblioteca padrão graças a generics.","Pages":[{"Title":"Generics - Channels","Content":"\n \u003ch2\u003eGenerics - Channels\u003c/h2\u003e\n \n \n \u003cp\u003e\n Explore como a equipe do Go poderia adicionar um pacote de padrões de concorrência à biblioteca padrão graças a generics.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Generics, que percorre todos os exemplos \n\n\n desta seção do Tour (vídeo em Inglês).\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Função Work\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2\u003c/b\u003e: Pooling\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicação\u003c/h2\u003e\n \n \n \u003cp\u003e\n Isso exigiria a declaração de channels e funções usando tipos generics.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype workFn[Result any] func(context.Context) Result\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste exemplo, é declarado um tipo que representa uma função que aceita um contexto e \n\n\n retorna um valor do tipo generic Result. Essa declaração de função descreve uma função \n\n\n que implementa o trabalho concorrente que será realizado e o resultado desse trabalho.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc doWork[Result any](ctx context.Context, work workFn[Result]) chan Result {\n ch := make(chan Result, 1)\n \n go func() {\n ch \u0026lt;- work(ctx)\n fmt.Println(\u0026#34;doWork : work complete\u0026#34;)\n }()\n \n return ch\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Agora, escreva uma função chamada doWork que execute a função de trabalho especificada \n\n\n de forma concorrente e retorne um channel para que o chamador possa receber o resultado \n\n\n do trabalho realizado pela função de trabalho. É declarado um tipo generic chamado Result \n\n\n para representar o tipo de retorno da função de trabalho e o tipo do channel.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Na implementação da função doWork, é construído um channel em buffer de tamanho um do tipo \n\n\n generic Result. Este é o channel retornado ao chamador para receber o resultado do trabalho \n\n\n concorrente. No meio da função, é criada uma goroutine para executar a função de trabalho \n\n\n de forma concorrente. Assim que a função de trabalho retornar, o argumento de retorno é \n\n\n enviado de volta ao chamador através do channel.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Para testar o uso da função doWork, construa um pequeno programa.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n duration := 100 * time.Millisecond\n \n ctx, cancel := context.WithTimeout(context.Background(), duration)\n defer cancel()\n \n dwf := func(ctx context.Context) string {\n time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)\n return \u0026#34;work complete\u0026#34;\n }\n\n result := doWork(ctx, dwf)\n \n select {\n case v := \u0026lt;-result:\n fmt.Println(\u0026#34;main:\u0026#34;, v)\n case \u0026lt;-ctx.Done():\n fmt.Println(\u0026#34;main: timeout\u0026#34;)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003edoWork : work complete\nmain: work complete\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O programa começa declarando um contexto que expirará em 100 milissegundos. Em seguida, \n\n\n é declarada uma função de trabalho que espera até 200 milissegundos antes de retornar a \n\n\n string \u0026#34;trabalho concluído\u0026#34;. Com o contexto e a função de trabalho no lugar, é feita \n\n\n uma chamada para doWork e um channel do tipo string é retornado e atribuído à variável resultado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O compilador é capaz de determinar o tipo concreto a ser usado para o tipo genérico Result, \n\n\n examinando o tipo de retorno da função de trabalho literal que é passada para a função doWork. \n\n\n Isso é brilhante porque significa que você não precisa passar o tipo na chamada para doWork.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Com o channel do tipo string atribuído à variável resultado, um caso de seleção é usado para \n\n\n aguardar o resultado ser retornado a tempo, ou para que ocorra o timeout. A função doWork pode \n\n\n ser usada para realizar este trabalho concorrente para qualquer tipo concreto necessário.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Essa mesma ideia poderia ser aplicada a um conjunto de goroutines que poderiam executar trabalho \n\n\n em uma entrada generic e retornar um resultado generic.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype workFn[Input any, Result any] func(input Input) Result\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste exemplo, altere o tipo de função para aceitar uma entrada generic e retornar um resultado generic.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc poolWork[Input any, Result any](size int, work workFn[Input, Result]) (chan Input, func()) {\n var wg sync.WaitGroup\n wg.Add(size)\n \n ch := make(chan Input)\n \n for i := 0; i \u0026lt; size; i\u0026#43;\u0026#43; {\n go func() {\n defer wg.Done()\n for input := range ch {\n result := work(input)\n fmt.Println(\u0026#34;pollWork :\u0026#34;, result)\n }\n }()\n }\n \n cancel := func() {\n close(ch)\n wg.Wait()\n }\n\n return ch, cancel\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Na função poolWork, os mesmos dois tipos generics são declarados para representar o \n\n\n tipo de entrada e retorno da função de trabalho. Um WaitGroup é construído para gerenciar \n\n\n o ciclo de vida das Goroutines no pool. Em seguida, é construído um channel do tipo de \n\n\n entrada generics. Este channel é usado pelas Goroutines no pool para receber os dados \n\n\n de entrada para a função de trabalho.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Em seguida, o pool de Goroutines é criado, com cada Goroutine aguardando em uma operação de \n\n\n recebimento usando um loop for-range contra o channel. Por fim, uma função de cancelamento é \n\n\n construída para permitir que o chamador desligue o pool e aguarde todas as Goroutines sinalizarem \n\n\n que terminaram.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Para testar o uso da função poolWork, construa um segundo programa pequeno.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n size := runtime.GOMAXPROCS(0)\n \n pwf := func(input int) string {\n time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)\n return fmt.Sprintf(\u0026#34;%d : received\u0026#34;, input)\n }\n\n ch, cancel := poolWork(size, pwf)\n defer cancel()\n \n for i := 0; i \u0026lt; 4; i\u0026#43;\u0026#43; {\n ch \u0026lt;- i\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epollWork : 3 : received\npollWork : 2 : received\npollWork : 1 : received\npollWork : 0 : received\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O tamanho do pool é calculado com base no número de Goroutines que podem ser executadas \n\n\n em paralelo. Em seguida, uma função de trabalho é criada para esperar por uma quantidade \n\n\n aleatória de tempo e depois retornar uma string que representa a entrada.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Com isso em vigor, a função poolWork é executada e o channel e a função de cancelamento \n\n\n são retornados. A função de cancelamento é adiada e um loop é construído para enviar 4 \n\n\n valores para o pool. A saída será diferente cada vez que você executar o programa, já \n\n\n que esse trabalho está acontecendo em paralelo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esses pequenos exemplos fornecem uma visão de como um pacote concorrente poderia ser implementado.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to execute a work function in a goroutine and\n// return a channel of type Result (to be determined later) back to the caller.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\ntype doworkFn[Result any] func(context.Context) Result\n\nfunc doWork[Result any](ctx context.Context, work doworkFn[Result]) chan Result {\n\tch := make(chan Result, 1)\n\n\tgo func() {\n\t\tch \u003c- work(ctx)\n\t\tfmt.Println(\"doWork : work complete\")\n\t}()\n\n\treturn ch\n}\n\nfunc main() {\n\tctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)\n\tdefer cancel()\n\n\tdwf := func(ctx context.Context) string {\n\t\ttime.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)\n\t\treturn \"work complete\"\n\t}\n\n\tselect {\n\tcase v := \u003c-doWork(ctx, dwf):\n\t\tfmt.Println(\"main:\", v)\n\tcase \u003c-ctx.Done():\n\t\tfmt.Println(\"main: timeout\")\n\t}\n}\n","Hash":"6dS3Wzip0LMSBbnh6i1QikV73y4="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to execute a work function via a pool of goroutines\n// and return a channel of type Input (to be determined later) back to the caller.\n// Once input is received by any given goroutine, the work function is executed\n// and the Result value is displayed.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype poolWorkFn[Input any, Result any] func(input Input) Result\n\nfunc poolWork[Input any, Result any](size int, work poolWorkFn[Input, Result]) (chan Input, func()) {\n\tvar wg sync.WaitGroup\n\twg.Add(size)\n\n\tch := make(chan Input)\n\n\tfor i := 0; i \u003c size; i++ {\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tfor input := range ch {\n\t\t\t\tresult := work(input)\n\t\t\t\tfmt.Println(\"pollWork :\", result)\n\t\t\t}\n\t\t}()\n\t}\n\n\tcancel := func() {\n\t\tclose(ch)\n\t\twg.Wait()\n\t}\n\n\treturn ch, cancel\n}\n\nfunc main() {\n\tsize := runtime.GOMAXPROCS(0)\n\tpwf := func(input int) string {\n\t\ttime.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)\n\t\treturn fmt.Sprintf(\"%d : received\", input)\n\t}\n\n\tch, cancel := poolWork(size, pwf)\n\tdefer cancel()\n\n\tfor i := 0; i \u003c 5; i++ {\n\t\tch \u003c- i\n\t}\n}\n","Hash":"MUNeHL1CBLOX1amACBmEclJ2sKI="}]}]} ,"generics-hash-table":{"Title":"Tabelas Hash","Description":"Uma tabela hash é um exemplo clássico de um tipo de contêiner que pode se beneficiar realmente de tipos generics.","Pages":[{"Title":"Generics - Tabelas Hash","Content":"\n \u003ch2\u003eGenerics - Tabelas Hash\u003c/h2\u003e\n \n \n \u003cp\u003e\n Uma tabela hash é um exemplo clássico de um tipo de contêiner que \n\n\n pode se beneficiar realmente de tipos generics. Essa implementação \n\n\n foi feita por Matt Layher (@mdlayer) em um artigo de blog que ele \n\n\n escreveu. É um ótimo exemplo do que é possível com generics.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Generics, que percorre todos os exemplos \n\n\n desta seção do Tour (vídeo em Inglês).\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Tabela Hash\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicação\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este código é um pouco mais complexo do que os que você viu até agora. É o que você \n\n\n pode esperar ver em implementações do mundo real. Ao longo desta seção, você verá \n\n\n duas versões do código: uma antes e outra depois de aplicar a nova sintaxe para generics.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype hashFunc func(key K, buckets int) int\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este type declara a assinatura de uma função de hash que é utilizada pela tabela hash \n\n\n para calcular a posição de um bucket para o armazenamento e recuperação de dados. O usuário \n\n\n deve implementar e fornecer essa função ao construir uma tabela hash. A função aceita uma \n\n\n chave e o número de buckets dos quais pode escolher. Como você deseja que esse sistema seja \n\n\n genérico em relação aos tipos usados para a chave e o valor, você declara um parâmetro \n\n\n chamado \u0026#34;key\u0026#34; com um tipo representado pela única letra maiúscula K.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A seguir, você pode aplicar a sintaxe de tipos generics para tornar K um tipo generic real.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype hashFunc[K comparable] func(key K, buckets int) int \u0026lt;-- CHANGED\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após o nome do type, adicione os colchetes com o tipo generic K e uma restrição de \n\n\n \u0026#34;comparable\u0026#34;. Uma vez que os valores do type de chave precisam ser usados em uma \n\n\n operação de comparação, documentar isso agora faz sentido, mesmo que a implementação \n\n\n da função de hash não o exija. A consistência é fundamental em termos de legibilidade, \n\n\n compreensão e manutenção ao longo do tempo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Este type representa um par de chave/valor de dados que será armazenado na tabela hash.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype keyValuePair struct {\n Key K\n Value V\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O objetivo deste type é armazenar os dados reais com a chave correspondente. Em seguida, \n\n\n o código declara um campo de chave do tipo K e um campo de valor do tipo V.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora você pode aplicar a sintaxe de generics para tornar K e V um tipo generic real.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype keyValuePair[K comparable, V any] struct { \u0026lt;-- CHANGED\n Key K\n Value V\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após o nome do type, adicione os colchetes com os tipos generic K e V. Nesta declaração, \n\n\n K representa a chave como antes e V representa um valor, que pode ser qualquer coisa.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Este type representa uma tabela hash que gerencia uma função de hash e um conjunto de \n\n\n buckets para armazenamento de dados de chave/valor.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Table struct {\n hashFunc hashFunc\n buckets int\n data [][]keyValuePair\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O tipo Table tem três campos: uma função de hash, o número de buckets e os dados, que são \n\n\n representados como um slice de um slice de pares chave/valor. O slice externa representa os \n\n\n buckets, e o slice interno representa os pares chave/valor que estão armazenados dentro de um bucket.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora, aplique a sintaxe de generics para declarar os tipos generics de chave e valor e aplique-os \n\n\n às declarações de campo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Table[K comparable, V any] struct { \u0026lt;-- CHANGED\n hashFunc hashFunc[K] \u0026lt;-- CHANGED\n buckets int\n data [][]keyValuePair[K, V] \u0026lt;-- CHANGED\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após o nome do type, adicione os colchetes com os tipos genéricos K e V. A declaração \n\n\n do tipo hashFunc requer informações sobre o tipo concreto a ser usado para a chave. \n\n\n A declaração do tipo keyValuePair requer informações sobre o tipo concreto para a chave \n\n\n e o valor.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esta é uma função de fábrica que pode construir uma Table para uso.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc New(\n buckets int,\n hf hashFunc\n) *Table {\n \n return \u0026amp;Table{\n hashFunc: hf,\n buckets: buckets,\n data: make([][]keyValuePair, buckets),\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função de fábrica aceita o número de buckets a serem gerenciados e uma função de hash \n\n\n para selecionar um bucket para armazenamento e busca de dados. Quando um valor do Table \n\n\n é construído, o número de buckets é usado para construir o slice, definindo o tamanho do \n\n\n slice externo para o número de buckets que serão usados.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora, aplique a sintaxe de generics para declarar os tipos generics de chave e valor e \n\n\n aplique-os aos tipos que precisam ser construídos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc New[K comparable, V any]( \u0026lt;-- CHANGED\n buckets int,\n hf hashFunc[K], \u0026lt;-- CHANGED\n) *Table[K, V] { \u0026lt;-- CHANGED\n \n return \u0026amp;Table[K, V]{ \u0026lt;-- CHANGED\n hashFunc: hf,\n buckets: buckets,\n data: make([][]keyValuePair[K, V], buckets), \u0026lt;-- CHANGED\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após o nome do type, adicione os colchetes e os tipos genéricos K e V. Em seguida, \n\n\n K é aplicado ao parâmetro de entrada hf para completar a declaração do tipo hashFunc. \n\n\n Os tipos K e V são aplicados ao tipo Table que está sendo construído e retornado. \n\n\n Por fim, a inicialização do campo de dados requer que K e V sejam aplicados à sintaxe \n\n\n de construção para o tipo keyValuePair.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Este é um método que pode inserir valores na tabela hash com base em uma chave especificada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Table[K comparable, V any] struct {\n hashFunc hashFunc[K]\n buckets int\n table [][]keyValuePair[K, V]\n}\n\nfunc (t *Table) Insert(key K, value V) {\n bucket := t.hashFunc(key, t.buckets)\n for idx, kvp := range t.table[bucket] {\n if key == kvp.Key {\n t.table[bucket][idx].Value = value\n return\n }\n }\n\n kvp := keyValuePair{\n Key: key,\n Value: value,\n }\n t.table[bucket] = append(t.table[bucket], kvp)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O método Insert é declarado para aceitar uma chave e um valor dos mesmos tipos genéricos \n\n\n que são declarados com o tipo Table. O primeiro passo para inserir é identificar o bucket \n\n\n a ser usado para o armazenamento. Isso é feito chamando a função de hash com a chave especificada. \n\n\n A função de hash retorna um valor inteiro que representa o bucket a ser usado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Em seguida, a função verifica se a chave especificada já foi usada para armazenar um valor no \n\n\n bucket selecionado. Isso é feito percorrendo o conjunto existente de pares chave/valor no bucket. \n\n\n Se a chave já existir, o valor para essa chave é atualizado. Se a chave não for encontrada, \n\n\n um novo valor de par chave/valor é construído, inicializado e adicionado à fatia para o bucket \n\n\n selecionado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora, aplique a sintaxe de generics para declarar os tipos generics de chave e valor e aplique-os \n\n\n aos tipos que precisam ser construídos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (t *Table[K, V]) Insert(key K, value V) { \u0026lt;-- CHANGED\n bucket := t.hashFunc(key, t.buckets)\n for idx, kvp := range t.table[bucket] {\n if key == kvp.Key {\n t.table[bucket][idx].Value = value\n return\n }\n }\n\n kvp := keyValuePair[K, V]{ \u0026lt;-- CHANGED\n Key: key,\n Value: value,\n }\n t.table[bucket] = append(t.table[bucket], kvp)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após o nome do type no receptor, adicione os colchetes e os tipos genéricos K e V. \n\n\n A única outra alteração é aplicar K e V à sintaxe de construção do tipo keyValuePair.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Este é um método que pode recuperar valores da tabela hash com base em uma chave especificada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (t *Table) Retrieve(key K) (V, bool) {\n bucket := t.hashFunc(key, t.buckets)\n for idx, kvp := range t.data[bucket] {\n if key == kvp.Key {\n return t.data[bucket][idx].Value, true\n }\n }\n\n var zero V\n return zero, false\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O método Retrieve é declarado para aceitar uma chave e retornar uma cópia do valor \n\n\n armazenado para essa chave. O primeiro passo ao recuperar é identificar o bucket que \n\n\n foi usado para o armazenamento. Isso é feito chamando a função de hash com a chave \n\n\n especificada. A função de hash retorna um valor inteiro que representa o bucket a ser \n\n\n examinado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Em seguida, a função itera sobre a coleção de pares chave/valor armazenados dentro do \n\n\n bucket, procurando a chave especificada um por um. Se a chave for encontrada, uma cópia \n\n\n do valor é retornada e verdadeiro é fornecido ao chamador. Se a chave não for encontrada, \n\n\n é retornado o valor zero e falso é fornecido ao chamador.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora, aplique a sintaxe de generics para declarar os tipos generics de chave e valor e \n\n\n aplique-os aos tipos que precisam ser construídos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (t *Table[K, V]) Get(key K) (V, bool) { \u0026lt;-- CHANGED\n bucket := t.hashFunc(key, t.buckets)\n for idx, kvp := range t.data[bucket] {\n if key == kvp.Key {\n return t.data[bucket][idx].Value, true\n }\n }\n\n var zero V\n return zero, false\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após o nome do type no receptor, adicione os colchetes e os tipos generics K e V. \n\n\n Nenhuma outra alteração de código é necessária.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Este é um pequeno programa para testar a implementação da tabela hash.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n const buckets = 8\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Comece com uma constante que define o número de buckets a serem usados na tabela hash.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eimport (\n \u0026#34;hash/fnv\u0026#34;\n)\n\nfunc main() {\n . . .\n \n hashFunc1 := func(key string, buckets int) int {\n h := fnv.New32()\n h.Write([]byte(key))\n return int(h.Sum32()) % buckets\n }\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A seguir, declare uma função de hash que declara uma string para a chave. A implementação \n\n\n utiliza o pacote fnv da biblioteca padrão, que implementa as funções de hash FNV-1 e FNV-1a, \n\n\n não criptográficas, criadas por Glenn Fowler, Landon Curt Noll e Phong Vo. FNV significa \n\n\n função de hash Fowler-Noll-Vo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A operação modulus com o valor de buckets força o valor final a cair dentro da faixa para o \n\n\n número de buckets.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eimport (\n \u0026#34;hash/fnv\u0026#34;\n)\n\nfunc main() {\n . . .\n \n table1 := New[/*key*/ string, /*value*/ int](buckets, hashFunc1)\n \n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A seguir, construa uma tabela hash, declarando explicitamente que a chave será do tipo string \n\n\n e o valor do tipo int. Não há nada nos parâmetros de entrada que possa ajudar o compilador a \n\n\n inferir essas informações.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Para mostrar a natureza generic da tabela hash, defina uma segunda função de hash e tabela.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eimport (\n \u0026#34;hash/fnv\u0026#34;\n)\n\nfunc main() {\n . . .\n\n hashFunc2 := func(key int, buckets int) int {\n return key % buckets\n }\n\n table2 := New[/*key*/ int, /*value*/ string](buckets, hashFunc2)\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Essa função de hash declara um inteiro para a chave e realiza uma simples operação modulus \n\n\n com o valor do bucket em relação à chave. Em seguida, uma nova tabela é construída onde \n\n\n a chave é especificada como um inteiro e o valor como uma string. É o inverso da primeira tabela.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eimport (\n \u0026#34;hash/fnv\u0026#34;\n)\n\nfunc main() {\n . . .\n\n words := []string{\u0026#34;foo\u0026#34;, \u0026#34;bar\u0026#34;, \u0026#34;baz\u0026#34;}\n for i, word := range words {\n table1.Insert(word, i)\n table2.Insert(i, word)\n }\n\n for i, s := range append(words, \u0026#34;nope!\u0026#34;) {\n v1, ok1 := table1.Retrieve(s)\n fmt.Printf(\u0026#34;t1.Rtr(%v) = (%v, %v)\\n\u0026#34;, s, v1, ok1)\n \n v2, ok2 := table2.Retrieve(i)\n fmt.Printf(\u0026#34;t2.Rtr(%v) = (%v, %v)\\n\u0026#34;, i, v2, ok2)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003et1.Rtr(foo) = (0, true)\nt2.Rtr(0) = (foo, true)\nt1.Rtr(bar) = (1, true)\nt2.Rtr(1) = (bar, true)\nt1.Rtr(baz) = (2, true)\nt2.Rtr(2) = (baz, true)\nt1.Rtr(nope!) = (0, false)\nt2.Rtr(3) = (, false)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Por fim, escreva código para armazenar e recuperar valores das duas respectivas tabelas.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This code is provided by Matt Layher (@mdlayher)\n// https://mdlayher.com/blog/go-generics-draft-design-building-a-hashtable/#a-generic-hashtable\n\n// Sample program to show how to write a generic hash table.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"hash/fnv\"\n)\n\n// =============================================================================\n\ntype hashFunc[K comparable] func(key K, buckets int) int\n\ntype keyValuePair[K comparable, V any] struct {\n\tKey K\n\tValue V\n}\n\ntype Table[K comparable, V any] struct {\n\thashFunc hashFunc[K]\n\tbuckets int\n\tdata [][]keyValuePair[K, V]\n}\n\nfunc New[K comparable, V any](buckets int, hf hashFunc[K]) *Table[K, V] {\n\treturn \u0026Table[K, V]{\n\t\thashFunc: hf,\n\t\tbuckets: buckets,\n\t\tdata: make([][]keyValuePair[K, V], buckets),\n\t}\n}\n\nfunc (t *Table[K, V]) Insert(key K, value V) {\n\tbucket := t.hashFunc(key, t.buckets)\n\n\tfor idx, kvp := range t.data[bucket] {\n\t\tif key == kvp.Key {\n\t\t\tt.data[bucket][idx].Value = value\n\t\t\treturn\n\t\t}\n\t}\n\n\tkvp := keyValuePair[K, V]{\n\t\tKey: key,\n\t\tValue: value,\n\t}\n\tt.data[bucket] = append(t.data[bucket], kvp)\n}\n\nfunc (t *Table[K, V]) Retrieve(key K) (V, bool) {\n\tbucket := t.hashFunc(key, t.buckets)\n\n\tfor idx, kvp := range t.data[bucket] {\n\t\tif key == kvp.Key {\n\t\t\treturn t.data[bucket][idx].Value, true\n\t\t}\n\t}\n\n\tvar zero V\n\treturn zero, false\n}\n\n// =============================================================================\n\nfunc main() {\n\tconst buckets = 8\n\n\thashFunc1 := func(key string, buckets int) int {\n\t\th := fnv.New32()\n\t\th.Write([]byte(key))\n\t\treturn int(h.Sum32()) % buckets\n\t}\n\ttable1 := New[ /*key*/ string /*value*/, int](buckets, hashFunc1)\n\n\thashFunc2 := func(key int, buckets int) int {\n\t\treturn key % buckets\n\t}\n\ttable2 := New[ /*key*/ int /*value*/, string](buckets, hashFunc2)\n\n\twords := []string{\"foo\", \"bar\", \"baz\"}\n\tfor i, word := range words {\n\t\ttable1.Insert(word, i)\n\t\ttable2.Insert(i, word)\n\t}\n\n\tfor i, s := range append(words, \"nope!\") {\n\t\tv1, ok1 := table1.Retrieve(s)\n\t\tfmt.Printf(\"t1.Rtr(%v) = (%v, %v)\\n\", s, v1, ok1)\n\n\t\tv2, ok2 := table2.Retrieve(i)\n\t\tfmt.Printf(\"t2.Rtr(%v) = (%v, %v)\\n\", i, v2, ok2)\n\t}\n}\n","Hash":"023N8uB5OtOdtAWV5jCiPF10+HI="}]}]} ,"algorithms-numbers":{"Title":"Operações Numéricas","Description":"Essa seção fornece exemplos que executam operações numéricas.","Pages":[{"Title":"Palíndromo","Content":"\n \u003ch2\u003ePalíndromo\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O programa de exemplo implementa uma verificação para ver se um inteiro é um\n\n\n palíndromo ou não.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Palindrome\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Palindrome\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eUm palíndromo é uma palavra, número, frase, ou outra sequência de símbolos que\npode ser lida da mesma forma de trás para frente.\n\n┌───┐┌───┐┌───┐\n│ 1 ││ 0 ││ 1 │ ────▷ Palíndromo\n└───┘└───┘└───┘\n\n┌───┐┌───┐┌───┐\n│ 1 ││ 2 ││ 3 │ ────▷ Não\n└───┘└───┘└───┘\n\n┌───┐\n│ 5 │ ────▷ Palíndromo\n└───┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"palindrome.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to determine if an integer is a\n// palindrome or not.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ttt := []int{-1, 1, 9, 10, 1001, 125}\n\n\tfor _, input := range tt {\n\t\tsuccess := IsPalindrome(input)\n\n\t\tswitch success {\n\t\tcase true:\n\t\t\tfmt.Printf(\"%d is a palindrome\\n\", input)\n\n\t\tcase false:\n\t\t\tfmt.Printf(\"%d is NOT a palindrome\\n\", input)\n\t\t}\n\t}\n}\n\n// IsPalindrome checks if a integer is a Palindrome.\nfunc IsPalindrome(input int) bool {\n\n\t// A negative integer is not a palindrome.\n\tif input \u003c 0 {\n\t\treturn false\n\t}\n\n\t// An integer that is only one digit in length is a palindrome.\n\tif input \u003e= 0 \u0026\u0026 input \u003c 10 {\n\t\treturn true\n\t}\n\n\t// Reverse the digits in the integer.\n\trev := Reverse(input)\n\n\treturn input == rev\n}\n\n// Reverse takes the specified integer and reverses it.\nfunc Reverse(num int) int {\n\n\t// Construct result to its zero value.\n\tvar result int\n\n\t// Loop until num is zero.\n\tfor num != 0 {\n\n\t\t// Perform a modulus operation to get the last digit from the value set in num.\n\t\t// https://www.geeksforgeeks.org/find-first-last-digits-number/\n\t\t// Ex. For num = 125, last = 5\n\t\tlast := num % 10\n\n\t\t// Multiple the current result by 10 to shift the digits in\n\t\t// the current result to the left.\n\t\t// Ex. For result = 5, result = 50\n\t\tresult = result * 10\n\n\t\t// Add the digit we took from the end of num to the result.\n\t\t// Ex. For result = 21 and last = 5, result = 215\n\t\tresult += last\n\n\t\t// Remove the digit we just reversed from num.\n\t\t// Ex. For num = 125, num = 12\n\t\tnum = num / 10\n\t}\n\n\treturn result\n}\n","Hash":"BaP9VQ9ywVnbX0f9EEy1S0Nc+RE="}]}]} ,"algorithms-sorting":{"Title":"Operações de ordenação","Description":"Esta seção fornece exemplos de operações de ordenação.","Pages":[{"Title":"Bubble Sort","Content":"\n \u003ch2\u003eBubble Sort\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eWatch The Video\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003eNeed Financial Assistance, Use Our \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eScholarship Form\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O programa de exemplo implementa uma função que realiza o bubble sort em um conjunto de números inteiros.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Bubble_sort\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Bubble_sort\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eBubble sort é um algoritmo simples de ordenação que percorre repetidamente a\nlista de entrada elemento por elemento, comparando o elemento atual com o\npróximo e trocando seus valores, se necessário.\n\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 10 ││ 30 ││ 05 ││ 25 ││ 15 │ ◁── Array inicial\n└────┘└────┘└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 10 ││ 05 ││ 25 ││ 15 ││ 30 │ ◁── Após a primeira iteração\n└────┘└────┘└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 05 ││ 10 ││ 15 ││ 25 ││ 30 │ ◁── Após a segunda iteração/ Ordenado\n└────┘└────┘└────┘└────┘└────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"bubble.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a bubble sort.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tnumbers := generateList(10)\n\tfmt.Println(\"Before:\", numbers)\n\n\tbubbleSort(numbers)\n\tfmt.Println(\"Sequential:\", numbers)\n}\n\nfunc bubbleSort(numbers []int) {\n\tn := len(numbers)\n\n\tfor i := 0; i \u003c n; i++ {\n\t\tif !sweep(numbers, i) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc sweep(numbers []int, currentPass int) bool {\n\tvar idx int\n\tvar swap bool\n\n\tidxNext := idx + 1\n\tn := len(numbers)\n\n\tfor idxNext \u003c (n - currentPass) {\n\t\ta := numbers[idx]\n\t\tb := numbers[idxNext]\n\n\t\tif a \u003e b {\n\t\t\tnumbers[idx] = b\n\t\t\tnumbers[idxNext] = a\n\t\t\tswap = true\n\t\t}\n\n\t\tidx++\n\t\tidxNext = idx + 1\n\t}\n\n\treturn swap\n}\n\nfunc generateList(totalNumbers int) []int {\n\tnumbers := make([]int, totalNumbers)\n\n\tfor i := 0; i \u003c totalNumbers; i++ {\n\t\tnumbers[i] = rand.Intn(totalNumbers * 20)\n\t}\n\n\treturn numbers\n}\n","Hash":"lhOJTqgOzYrVNILHnySSxlnecbk="}]},{"Title":"Insertion Sort","Content":"\n \u003ch2\u003eInsertion Sort\u003c/h2\u003e\n \n \n \u003cp\u003e\n O programa de exemplo implementa uma função que realiza a ordenação por inserção (insertion sort)\n\n\n em um conjunto de números inteiros.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Insertion_sort\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Insertion_sort\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n\n\n A ordenação por inserção itera o mesmo número de vezes que o comprimento da\n\n\n array menos um. Para uma array com 5 números, a ordenação iterará 4 vezes. \n\n\n Começando no índice 1, a ordenação move esse número para a esquerda,\n\n\n colocando-o em uma posição ordenada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Array inicial\n│ 10 ││ 30 ││ 05 ││ 25 ││ 15 │ ◁── Mova [1]=30 para a esquerda\n└────┘└────┘└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Após a primeira iteração\n│ 10 ││ 30 ││ 05 ││ 25 ││ 15 │ ◁── Mova [2]=05 para a esquerda\n└────┘└────┘└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Após a segunda iteração\n│ 05 ││ 10 ││ 30 ││ 25 ││ 15 │ ◁── Mova [3]=25 para a esquerda\n└────┘└────┘└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Após a terceira iteração\n│ 05 ││ 10 ││ 25 ││ 30 ││ 15 │ ◁── Mova [4]=15 para a esquerda\n└────┘└────┘└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Após a quarta iteração\n│ 05 ││ 10 ││ 15 ││ 25 ││ 30 │ ◁── Ordenado\n└────┘└────┘└────┘└────┘└────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"insertion.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a insertion sort.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tnumbers := generateList(10)\n\tfmt.Println(\"Before:\", numbers)\n\n\tinsertionSort(numbers)\n\tfmt.Println(\"Sequential:\", numbers)\n}\n\nfunc insertionSort(numbers []int) {\n\tvar n = len(numbers)\n\n\t// Walk through the numbers from left to right. Through\n\t// each outer loop iteration we move values from right\n\t// to left inside the array when they are larger than\n\t// the value that precedes it.\n\n\tfor i := 1; i \u003c n; i++ {\n\t\tj := i\n\n\t\t// For the given starting i index position, look\n\t\t// for smaller values to move left down the numbers list.\n\n\t\tfor j \u003e 0 {\n\n\t\t\t// Is the value on the left larger than the\n\t\t\t// right. If true, swap the two values.\n\n\t\t\tif numbers[j-1] \u003e numbers[j] {\n\t\t\t\tnumbers[j-1], numbers[j] = numbers[j], numbers[j-1]\n\t\t\t}\n\n\t\t\t// Walk through the item from right to left.\n\n\t\t\tj--\n\t\t}\n\t}\n}\n\nfunc generateList(totalNumbers int) []int {\n\tnumbers := make([]int, totalNumbers)\n\n\tfor i := 0; i \u003c totalNumbers; i++ {\n\t\tnumbers[i] = rand.Intn(totalNumbers * 20)\n\t}\n\n\treturn numbers\n}\n","Hash":"kPNaon7S933mJ3Wef0pENPnsRY4="}]},{"Title":"Heap Sort","Content":"\n \u003ch2\u003eHeap Sort\u003c/h2\u003e\n \n \n \u003cp\u003e\n O programa de exemplo implementa uma função que realiza a ordenação por heap em um conjunto de números inteiros.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Heapsort\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Heapsort\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A ordenação por heap divide sua entrada em uma array ordenada e uma não ordenada. \n\n\n O algoritmo encolhe iterativamente a região não ordenada, extraindo o elementomaior dela e inserindo-o na array ordenada. \n\n\n O algoritmo é executado em duas fases.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eFase I \nDivide a lista ao meio e trabalha com a metade frontal da lista, \nmovendo o maior valor que encontramos para a parte da frente da lista e depois o segundo maior.\n\n┌────┐┌────┐ | ┌────┐┌────┐┌────┐ ◁── Array inicial\n│ 63 ││ 16 │ | │ 40 ││ 71 ││ 73 │ ◁── Verifique [1]=16 \u0026lt; [4]=73 : Troque\n└────┘└────┘ | └────┘└────┘└────┘\n┌────┐┌────┐ | ┌────┐┌────┐┌────┐ ◁── Após a primeira iteração\n│ 63 ││ 73 │ | │ 40 ││ 71 ││ 16 │ ◁── Verifique [0]=63 \u0026lt; [3]=71 : Troque\n└────┘└────┘ | └────┘└────┘└────┘\n┌────┐┌────┐ | ┌────┐┌────┐┌────┐ ◁── Após segunda iteração\n│ 73 ││ 71 │ | │ 40 ││ 63 ││ 16 │ ◁── Fase I Completa\n└────┘└────┘ | └────┘└────┘└────┘\n\nFase II \nPegue a lista e comece a mover os números para fora e para uma nova lista\nordenada. Pegue o número na primeira posição e remova-o para a nova lista,\nque conterá a ordenação final. Em seguida, mova novamente o maior número que\nencontrarmos para a parte da frente da lista.\n\n┌────┐┌────┐┌────┐┌────┐┌────┐ | ◁── Array inicial\n│ 73 ││ 71 ││ 40 ││ 63 ││ 16 │ |\n└────┘└────┘└────┘└────┘└────┘ |\n┌────┐┌────┐┌────┐┌────┐ | ┌────┐ ◁── Após a primeira iteração\n│ 71 ││ 63 ││ 40 ││ 16 │ | │ 73 │ ◁── Mova 73 para fora e 71 para frente\n└────┘└────┘└────┘└────┘ | └────┘\n┌────┐┌────┐┌────┐ | ┌────┐┌────┐ ◁── Após a segunda iteração\n│ 63 ││ 16 ││ 40 │ | │ 71 ││ 73 │ ◁── Mova 71 para fora e 63 para frente\n└────┘└────┘└────┘ | └────┘└────┘\n┌────┐┌────┐ | ┌────┐┌────┐┌────┐ ◁── Após a terceira iteração\n│ 40 ││ 16 │ | │ 63 ││ 71 ││ 73 │ ◁── Mova 71 para fora e 40 para frente\n└────┘└────┘ | └────┘└────┘└────┘\n┌────┐ | ┌────┐┌────┐┌────┐┌────┐ ◁── Após a quarta iteração\n│ 16 │ | │ 40 ││ 63 ││ 71 ││ 73 │ ◁── Mova 71 para fora e 16 para frente\n└────┘ | └────┘└────┘└────┘└────┘\n | ┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Após a quinta iteração\n | │ 16 ││ 40 ││ 63 ││ 71 ││ 73 │ ◁── Mova 16 para fora / Ordenado\n | └────┘└────┘└────┘└────┘└────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"heap.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a heap sort.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tnumbers := generateList(10)\n\tfmt.Println(\"Before:\", numbers)\n\n\theapSort(numbers)\n\tfmt.Println(\"Sequential:\", numbers)\n}\n\nfunc heapSort(numbers []int) []int {\n\n\t// Split the list in half and work the front half of the list, moving\n\t// the largest value we find to the front of the list and then the\n\t// second largest.\n\n\tfor index := (len(numbers) / 2) - 1; index \u003e= 0; index-- {\n\t\tnumbers = moveLargest(numbers, len(numbers), index)\n\t}\n\n\t// Take the list and start moving numbers out and into a new sorted\n\t// list. Take the number in the first position and remove it to the\n\t// new list which will contain the final sort. Then move the largest\n\t// number we find once again to the front of the list.\n\n\tsize := len(numbers)\n\tfor index := size - 1; index \u003e= 1; index-- {\n\t\tnumbers[0], numbers[index] = numbers[index], numbers[0]\n\t\tsize--\n\t\tnumbers = moveLargest(numbers, size, 0)\n\t}\n\n\treturn numbers\n}\n\n// moveLargest starts at the index positions specified in the list and attempts\n// to move the largest number it can find to that position in the list.\nfunc moveLargest(numbers []int, size int, index int) []int {\n\n\t// Calculate the index deviation so numbers in the list can be\n\t// compared and swapped if needed.\n\t// index 0: cmpIdx1: 1 cmpIdx2: 2 index 5: cmpIdx1: 11 cmpIdx2: 12\n\t// index 1: cmpIdx1: 3 cmpIdx2: 4 index 6: cmpIdx1: 13 cmpIdx2: 14\n\t// index 2: cmpIdx1: 5 cmpIdx2: 6 index 7: cmpIdx1: 15 cmpIdx2: 16\n\t// index 3: cmpIdx1: 7 cmpIdx2: 8 index 8: cmpIdx1: 17 cmpIdx2: 19\n\t// index 4: cmpIdx1: 9 cmpIdx2: 10 index 9: cmpIdx1: 19 cmpIdx2: 20\n\tcmpIdx1, cmpIdx2 := 2*index+1, 2*index+2\n\n\t// Save the specified index as the index with the current largest value.\n\tlargestValueIdx := index\n\n\t// Check if the value at the first deviation index is greater than\n\t// the value at the current largest index. If so, save that\n\t// index position.\n\tif cmpIdx1 \u003c size \u0026\u0026 numbers[cmpIdx1] \u003e numbers[largestValueIdx] {\n\t\tlargestValueIdx = cmpIdx1\n\t}\n\n\t// Check the second deviation index is within bounds and is greater\n\t// than the value at the current largest index. If so, save that\n\t// index position.\n\tif cmpIdx2 \u003c size \u0026\u0026 numbers[cmpIdx2] \u003e numbers[largestValueIdx] {\n\t\tlargestValueIdx = cmpIdx2\n\t}\n\n\t// If we found a larger value than the value at the specified index, swap\n\t// those numbers and then recurse to find more numbers to swap from that\n\t// point in the list.\n\tif largestValueIdx != index {\n\t\tnumbers[index], numbers[largestValueIdx] = numbers[largestValueIdx], numbers[index]\n\t\tnumbers = moveLargest(numbers, size, largestValueIdx)\n\t}\n\n\treturn numbers\n}\n\nfunc generateList(totalNumbers int) []int {\n\tnumbers := make([]int, totalNumbers)\n\n\tfor i := 0; i \u003c totalNumbers; i++ {\n\t\tnumbers[i] = rand.Intn(totalNumbers * 20)\n\t}\n\n\treturn numbers\n}\n","Hash":"L2NS4PKCOFsUJHagROixCaBBtOA="}]},{"Title":"Quick Sort","Content":"\n \u003ch2\u003eQuick Sort\u003c/h2\u003e\n \n \n \u003cp\u003e\n O programa de exemplo implementa uma função que realiza a ordenação rápida (Quick sort)\n\n\n em um conjunto de números inteiros.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Quicksort\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Quicksort\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eO Quicksort é um algoritmo de divisão e conquista. Funciona selecionando um\nelemento \u0026#39;pivô\u0026#39; da array e particionando os outros elementos em duas sub-arrays,\nde acordo com se são menores ou maiores que o pivô.\n\n-------------------------------------------------------------------\nExemplo 1\n┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Array inicial\n│ 45 ││ 39 ││ 37 ││ 15 ││ 41 │ ◁── Pivô de valor 41\n└────┘└────┘└────┘└────┘└────┘ ◁── Ordenar elementos 0 - 4\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 39 ││ 37 ││ 15 ││ 41 ││ 45 │ ◁── Primeira ordenação completa\n└────┘└────┘└────┘└────┘└────┘\n\nOs dois últimos elementos estão ordenados; concentre-se nos três primeiros.\n\n┌────┐┌────┐┌────┐\n│ 39 ││ 37 ││ 15 │ ◁── Pivô de valor 15\n└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 15 ││ 37 ││ 39 ││ 41 ││ 45 │ ◁── Ordenado\n└────┘└────┘└────┘└────┘└────┘\n\n-------------------------------------------------------------------\nExemplo 2\n┌────┐┌────┐┌────┐┌────┐┌────┐ ◁── Array inicial\n│ 34 ││ 55 ││ 59 ││ 73 ││ 09 │ ◁── Pivô de valor 09\n└────┘└────┘└────┘└────┘└────┘ ◁── Ordenar elementos 0 - 4\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 09 ││ 55 ││ 59 ││ 73 ││ 34 │ ◁── Primeira ordenação completa\n└────┘└────┘└────┘└────┘└────┘\n\nPrimeiro elemento está ordenado, foco nos últimos quatro.\n\n┌────┐┌────┐┌────┐┌────┐\n│ 55 ││ 59 ││ 73 ││ 34 │ ◁── Pivô de valor 34\n└────┘└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 09 ││ 34 ││ 59 ││ 73 ││ 55 │ ◁── Segunda Ordenação Concluída\n└────┘└────┘└────┘└────┘└────┘\n\n Os dois primeiros elementos estão ordenados, foco nos últimos três.\n\n┌────┐┌────┐┌────┐\n│ 59 ││ 73 ││ 55 │ ◁── Pivô de valor 55\n└────┘└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 09 ││ 34 ││ 55 ││ 73 ││ 59 │ ◁── Terceira Ordenação Concluída\n└────┘└────┘└────┘└────┘└────┘\n\nOs três primeiros elementos estão ordenados, foco nos últimos dois.\n\n┌────┐┌────┐ ◁── Pivô de valor 59\n│ 73 ││ 59 │ ◁── Terceira Ordenação Concluída\n└────┘└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 09 ││ 34 ││ 55 ││ 59 ││ 73 │ ◁── Ordenado\n└────┘└────┘└────┘└────┘└────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"quick.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a quick sort.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tnumbers := generateList(5)\n\tfmt.Println(\"Before:\", numbers)\n\n\tQuickSort(numbers)\n\tfmt.Println(\"Sequential:\", numbers)\n}\n\nfunc QuickSort(numbers []int) []int {\n\treturn quickSort(numbers, 0, len(numbers)-1)\n}\n\nfunc quickSort(numbers []int, leftIdx, rightIdx int) []int {\n\tswitch {\n\tcase leftIdx \u003e rightIdx:\n\t\treturn numbers\n\n\t// Divides array into two partitions.\n\tcase leftIdx \u003c rightIdx:\n\t\tnumbers, pivotIdx := partition(numbers, leftIdx, rightIdx)\n\n\t\tquickSort(numbers, leftIdx, pivotIdx-1)\n\t\tquickSort(numbers, pivotIdx+1, rightIdx)\n\t}\n\n\treturn numbers\n}\n\n// partition it takes a portion of an array then sort it.\nfunc partition(numbers []int, leftIdx, rightIdx int) ([]int, int) {\n\tpivot := numbers[rightIdx]\n\n\tfor smallest := leftIdx; smallest \u003c rightIdx; smallest++ {\n\t\tif numbers[smallest] \u003c pivot {\n\t\t\tnumbers[smallest], numbers[leftIdx] = numbers[leftIdx], numbers[smallest]\n\t\t\tleftIdx++\n\t\t}\n\t}\n\n\tnumbers[leftIdx], numbers[rightIdx] = numbers[rightIdx], numbers[leftIdx]\n\n\treturn numbers, leftIdx\n}\n\nfunc generateList(totalNumbers int) []int {\n\tnumbers := make([]int, totalNumbers)\n\n\tfor i := 0; i \u003c totalNumbers; i++ {\n\t\tnumbers[i] = rand.Intn(totalNumbers * 20)\n\t}\n\n\treturn numbers\n}\n","Hash":"pboWDwXjEtQQX6EdYLalNk2/RUY="}]}]} ,"algorithms-strings":{"Title":"Operações com Strings","Description":"Esta seção fornece exemplos que realizam operações em strings.","Pages":[{"Title":"Permutação","Content":"\n \u003ch2\u003ePermutação\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira? Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O programa exemplo implementa uma verificação para ver se uma string é ou não uma permutação.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Permutation\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Permutation\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eA permutação de uma string é o conjunto de todas as strings em que\ncontêm os mesmos caracteres sem importar a ordem da combinação de caracteres\n\n┌───┐┌───┐┌───┐\n│ G ││ O ││ D │ ──────┐\n└───┘└───┘└───┘ │ ────▷ Permutação\n┌───┐┌───┐┌───┐ │\n│ D ││ O ││ G │ ──────┘\n└───┘└───┘└───┘\n\n┌───┐┌───┐┌───┐\n│ G ││ O ││ D │ ──────┐\n└───┘└───┘└───┘ │ ────▷ NÃO\n┌───┐┌───┐ │\n│ D ││ O │ ──────┘\n└───┘└───┘\n\n┌───┐┌───┐┌───┐\n│ 1 ││ 0 ││ 0 │ ──────┐\n└───┘└───┘└───┘ │ ────▷ Permutação\n┌───┐┌───┐┌───┐ │\n│ 0 ││ 0 ││ 1 │ ──────┘\n└───┘└───┘└───┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"permutation.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to determine if a string is a\n// permutation or not.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\ttt := []struct {\n\t\tinput1 string\n\t\tinput2 string\n\t}{\n\t\t{\"\", \"\"},\n\t\t{\"god\", \"dog\"},\n\t\t{\"god\", \"do\"},\n\t\t{\"1001\", \"0110\"},\n\t}\n\n\tfor _, test := range tt {\n\t\tsuccess := IsPermutation(test.input1, test.input2)\n\n\t\tswitch success {\n\t\tcase true:\n\t\t\tfmt.Printf(\"%q and %q is a permutation\\n\", test.input1, test.input2)\n\n\t\tcase false:\n\t\t\tfmt.Printf(\"%q and %q is NOT a permutation\\n\", test.input1, test.input2)\n\t\t}\n\t}\n}\n\n// =============================================================================\n\n// RuneSlice a custom type of a slice of runes.\ntype RuneSlice []rune\n\n// For sorting an RuneSlice.\nfunc (p RuneSlice) Len() int { return len(p) }\nfunc (p RuneSlice) Less(i, j int) bool { return p[i] \u003c p[j] }\nfunc (p RuneSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n\n// IsPermutation check if two strings are permutations.\nfunc IsPermutation(str1, str2 string) bool {\n\n\t// If the length are not equal they cannot be permutation.\n\tif len(str1) != len(str2) {\n\t\treturn false\n\t}\n\n\t// Convert each string into a collection of runes.\n\ts1 := []rune(str1)\n\ts2 := []rune(str2)\n\n\t// Sort each collection of runes.\n\tsort.Sort(RuneSlice(s1))\n\tsort.Sort(RuneSlice(s2))\n\n\t// Convert the collection of runes back to a string\n\t// and compare.\n\treturn string(s1) == string(s2)\n}\n","Hash":"wCQOzXyuqZ9oGkkfc09bEN6NbW8="}]},{"Title":"Palíndromo","Content":"\n \u003ch2\u003ePalíndromo\u003c/h2\u003e\n \n \n \u003cp\u003e\n O programa exemplo implementa uma verificação para ver se a string\n\n\n é ou não palíndromo. \n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em \u003ca href=\"https://en.wikipedia.org/wiki/Palindrome\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Palindrome\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eUm palíndromo é uma palavra, número, frase, ou outra sequência de símbolos que\nsão lidos igualmente de trás pra frente.\n\n┌───┐┌───┐┌───┐\n│ B ││ O ││ B │ ────▷ Palíndromo\n└───┘└───┘└───┘\n\n┌───┐┌───┐┌───┐\n│ T ││ E ││ D │ ────▷ NÃO\n└───┘└───┘└───┘\n\n┌───┐\n│ G │ ────▷ Palíndromo\n└───┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"palindrome.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to determine if a string is a\n// palindrome or not.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ttt := []string{\"\", \"G\", \"bob\", \"otto\", \"汉字汉\", \"test\"}\n\n\tfor _, input := range tt {\n\t\tsuccess := IsPalindrome(input)\n\n\t\tswitch success {\n\t\tcase true:\n\t\t\tfmt.Printf(\"%q is a palindrome\\n\", input)\n\n\t\tcase false:\n\t\t\tfmt.Printf(\"%q is NOT a palindrome\\n\", input)\n\t\t}\n\t}\n}\n\n// =============================================================================\n\n// IsPalindrome checks if a string is a Palindrome.\nfunc IsPalindrome(input string) bool {\n\n\t// If the input string is empty or as a length of 1 return true.\n\tif input == \"\" || len(input) == 1 {\n\t\treturn true\n\t}\n\n\t// Convert the input string into slice of runes for processing.\n\t// A rune represent a code point in the UTF-8 character set.\n\trunes := []rune(input)\n\n\t// Run over runes forward and backward comparing runes.\n\t// If runes[i] != runes[len(runes)-i-1] then it's not a palindrome.\n\tfor i, j := 0, len(runes)-1; i \u003c j; i, j = i+1, j-1 {\n\t\tif runes[i] != runes[j] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n","Hash":"KaZOiqhjgC1ycMeWIjDnrniPf9s="}]}]} ,"error-handling":{"Title":"Tratamento de Erros","Description":"Tratamento de Erros é fundamental para tornar seus programas confiáveis, dignos de confiança e respeitosos com aqueles que dependem deles. ","Pages":[{"Title":"Design de Tratamento de Erros","Content":"\n \u003ch2\u003eDesign de Tratamento de Erros\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n A integridade é importante e faz parte fundamental do processo de engenharia. No cerne da integridade está o tratamento de erros. Quando se trata de Go, o tratamento de erros não é uma exceção a ser tratada posteriormente ou em algum outro lugar no código. Ele faz parte do caminho principal e precisa ser uma preocupação principal.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Os desenvolvedores têm a responsabilidade de fornecer contexto suficiente sobre qualquer erro, para que um usuário possa tomar uma decisão informada sobre como proceder. O tratamento de um erro envolve três coisas: registrar o erro, não propagar o erro mais adiante e determinar se a Goroutine/programa precisa ser encerrado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Em Go, os erros são apenas valores, então eles podem ser qualquer coisa que você precise que sejam. Eles podem manter qualquer estado ou comportamento.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Valores de Erro Padrão\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Variáveis de Erro\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Tipo como Contexto\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Comportamento como Contexto\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Encontrar o Erro\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e Encapsulando Erros com a stdlib\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eFundamentos do Tratamento de Erros\u003c/h2\u003e\n \n \n \u003cp\u003e\n A interface de erro está incorporada na linguagem.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// https://golang.org/pkg/builtin/#error\ntype error interface {\n Error() string\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Por isso, parece ser um identificador não exportado. Qualquer valor concreto que implementa esta interface pode ser usado como um valor de erro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Um aspecto importante do Go é que o tratamento de erros é feito em um estado desacoplado por meio desta interface. Uma razão importante para isso é porque o tratamento de erros é um aspecto da minha aplicação que está mais suscetível a mudanças e melhorias. Esta interface é o tipo que as aplicações em Go devem usar como tipo de retorno para o tratamento de erros.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// https://golang.org/src/pkg/errors/errors.go\ntype errorString struct {\n s string\n}\n\n// https://golang.org/src/pkg/errors/errors.go\nfunc (e *errorString) Error() string {\n return e.s\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este é o valor de erro mais comumente usado em programas Go. Ele é declarado no pacote \u0026#34;errors\u0026#34; da biblioteca padrão. Observe como o tipo é não exportado e possui um campo não exportado que é uma string. Você também pode ver como a semântica de ponteiro é usada para implementar a interface de erro. Isso significa que apenas endereços para valores desse tipo podem ser compartilhados e armazenados dentro da interface. O método simplesmente retorna a string de erro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n É importante lembrar que a implementação do método Error serve ao propósito de implementar a interface e para o registro de logs. Se algum usuário precisar analisar a string retornada por este método, você falhou em fornecer ao usuário a quantidade certa de contexto para tomar uma decisão informada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// https://golang.org/src/pkg/errors/errors.go\nfunc New(text string) error {\n return \u0026amp;errorString{text}\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função \u0026#34;New\u0026#34; é usada para construir um erro usando o tipo concreto \u0026#34;errorString\u0026#34;. Observe como a função retorna o erro usando a interface de erro. Também observe como as semânticas de ponteiro estão sendo usadas.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n if err := webCall(); err != nil {\n fmt.Println(err)\n return\n }\n fmt.Println(\u0026#34;Life is good\u0026#34;)\n}\n\nfunc webCall() error {\n return New(\u0026#34;bad request\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O contexto é fundamental quando se trata de erros. Cada erro deve fornecer contexto suficiente para permitir que o chamador tome uma decisão informada sobre o estado da goroutine/aplicação. Neste exemplo, a função \u003ccode\u003ewebCall\u003c/code\u003e retorna um erro com a mensagem `Bad Request`. Na função principal, é feita uma chamada para \u003ccode\u003ewebCall\u003c/code\u003e e, em seguida, é feita uma verificação para ver se ocorreu algum erro com a chamada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eif err := webCall(); err != nil {\n fmt.Println(err)\n return\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A chave para a verificação é `err != nil`. O que essa condição está perguntando é se há um valor concreto armazenado dentro do valor da interface \u003ccode\u003eerr\u003c/code\u003e. Quando o valor da interface está armazenando um valor concreto, há um erro. Neste caso, o contexto é literalmente apenas o fato de que um valor concreto existe, não importa qual seja o valor concreto.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n E se for importante saber qual valor de erro existe dentro da variável de interface \u003ccode\u003eerr\u003c/code\u003e? Nesse caso, as variáveis de erro são uma boa opção.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar (\n ErrBadRequest = errors.New(\u0026#34;Bad Request\u0026#34;)\n ErrPageMoved = errors.New(\u0026#34;Page Moved\u0026#34;)\n)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n As variáveis de erro fornecem um mecanismo para identificar qual erro específico está sendo retornado. Elas seguem a convenção de começar com o prefixo \u003ccode\u003eErr\u003c/code\u003e e são baseadas no tipo concreto \u003ccode\u003eerrorString\u003c/code\u003e do pacote \u003ccode\u003eerrors\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc webCall(b bool) error {\n if b {\n return ErrBadRequest\n }\n return ErrPageMoved\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Nesta nova versão da função \u003ccode\u003ewebCall\u003c/code\u003e, a função retorna uma das duas variáveis de erro. Isso permite que o chamador determine qual erro ocorreu.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n if err := webCall(true); err != nil {\n switch err {\n case ErrBadRequest:\n fmt.Println(\u0026#34;Bad Request Occurred\u0026#34;)\n return\n\n case ErrPageMoved:\n fmt.Println(\u0026#34;The Page moved\u0026#34;)\n return\n\n default:\n fmt.Println(err)\n return\n }\n }\n\n fmt.Println(\u0026#34;Life is good\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Na aplicação, após a chamada para a função \u003ccode\u003ewebCall\u003c/code\u003e, é possível verificar se há um valor concreto armazenado dentro da variável de interface \u003ccode\u003eerr\u003c/code\u003e. Se houver, então uma declaração \u003ccode\u003eswitch\u003c/code\u003e é usada para determinar qual erro ocorreu, comparando \u003ccode\u003eerr\u003c/code\u003e com as diferentes variáveis de erro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nesse caso, o contexto do erro é baseado em qual variável de erro foi retornada. No entanto, se uma variável de erro não fornecer contexto suficiente, ou se for necessário verificar algum estado especial, como em erros de rede, nesses casos, a resposta é usar um tipo concreto de erro personalizado. Isso permitirá definir um tipo de erro personalizado que pode conter informações adicionais específicas sobre o erro, proporcionando assim um contexto mais detalhado para o tratamento de erros.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype UnmarshalTypeError struct {\n Value string\n Type reflect.Type\n}\n\nfunc (e *UnmarshalTypeError) Error() string {\n return \u0026#34;json: cannot unmarshal \u0026#34; \u0026#43; e.Value \u0026#43;\n \u0026#34; into Go value of type \u0026#34; \u0026#43; e.Type.String()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este é um tipo de erro concreto personalizado implementado no pacote \u003ccode\u003ejson\u003c/code\u003e. Observe que o nome tem um sufixo \u003ccode\u003eError\u003c/code\u003e na nomenclatura do tipo. Também observe o uso de semântica de ponteiro para a implementação da interface de erro. Mais uma vez, a implementação destina-se ao registro de logs e deve exibir informações sobre todos os campos capturados.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype InvalidUnmarshalError struct {\n Type reflect.Type\n}\n\nfunc (e *InvalidUnmarshalError) Error() string {\n if e.Type == nil {\n return \u0026#34;json: Unmarshal(nil)\u0026#34;\n }\n if e.Type.Kind() != reflect.Ptr {\n return \u0026#34;json: Unmarshal(non-pointer \u0026#34; \u0026#43; e.Type.String() \u0026#43; \u0026#34;)\u0026#34;\n }\n return \u0026#34;json: Unmarshal(nil \u0026#34; \u0026#43; e.Type.String() \u0026#43; \u0026#34;)\u0026#34;\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este é um segundo tipo de erro concreto personalizado encontrado no pacote \u003ccode\u003ejson\u003c/code\u003e. A implementação do método \u003ccode\u003eError\u003c/code\u003e é um pouco mais complexa, mas, mais uma vez, é destinada apenas ao registro de logs e usa semântica de ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Unmarshal(data []byte, v interface{}) error {\n rv := reflect.ValueOf(v)\n if rv.Kind() != reflect.Ptr || rv.IsNil() {\n return \u0026amp;InvalidUnmarshalError{reflect.TypeOf(v)}\n }\n return \u0026amp;UnmarshalTypeError{\u0026#34;string\u0026#34;, reflect.TypeOf(v)}\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui está uma parte da função \u003ccode\u003eUnmarshal\u003c/code\u003e. Observe como ela constrói os valores de erro concretos no retorno, passando-os de volta para o chamador por meio da interface de erro. A construção com semântica de ponteiro está sendo usada porque a semântica de ponteiro foi usada na declaração do método \u003ccode\u003eError\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O contexto do erro aqui está mais relacionado ao tipo de erro armazenado dentro da interface de erro. Precisa haver uma maneira de determinar isso.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n var u user\n err := Unmarshal([]byte(`{\u0026#34;name\u0026#34;:\u0026#34;bill\u0026#34;}`), u)\n if err != nil {\n switch e := err.(type) {\n case *UnmarshalTypeError:\n fmt.Printf(\u0026#34;UnmarshalTypeError: Value[%s] Type[%v]\\n\u0026#34;,\n e.Value, e.Type)\n case *InvalidUnmarshalError:\n fmt.Printf(\u0026#34;InvalidUnmarshalError: Type[%v]\\n\u0026#34;, e.Type)\n default:\n fmt.Println(err)\n }\n return\n }\n fmt.Println(\u0026#34;Name:\u0026#34;, u.Name)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Uma asserção de tipo genérica dentro do escopo da declaração \u003ccode\u003eswitch\u003c/code\u003e é como você pode escrever código para testar que tipo de valor está armazenado dentro da variável de interface \u003ccode\u003eerr\u003c/code\u003e. O tipo é o contexto aqui e agora você pode testar e tomar ação com acesso a todos os estados do erro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n No entanto, isso apresenta um problema. Não estou mais desacoplado do valor de erro concreto. Isso significa que se o valor de erro concreto for alterado, meu código pode quebrar. A parte bonita de usar uma interface para o tratamento de erros é estar desacoplado de mudanças que quebram o código.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se o valor de erro concreto tiver um conjunto de métodos, então você pode usar uma interface para a verificação de tipo. Como exemplo, o pacote \u003ccode\u003enet\u003c/code\u003e tem muitos tipos de erro concretos que implementam diferentes métodos. Um método comum é chamado de \u003ccode\u003eTemporary\u003c/code\u003e (Temporário). Esse método permite que o usuário teste se o erro de rede é crítico ou apenas algo que pode se recuperar por conta própria.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype temporary interface {\n Temporary() bool\n}\n\nfunc (c *client) BehaviorAsContext() {\n for {\n line, err := c.reader.ReadString(\u0026#39;\\n\u0026#39;)\n if err != nil {\n switch e := err.(type) {\n case temporary:\n if !e.Temporary() {\n log.Println(\u0026#34;Temporary: Client leaving chat\u0026#34;)\n return\n }\n default:\n if err == io.EOF {\n log.Println(\u0026#34;EOF: Client leaving chat\u0026#34;)\n return\n }\n log.Println(\u0026#34;read-routine\u0026#34;, err)\n }\n }\n fmt.Println(line)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste código, a chamada para \u003ccode\u003eReadString\u003c/code\u003e pode falhar com um erro do pacote \u003ccode\u003enet\u003c/code\u003e. Nesse caso, uma interface é declarada que representa o comportamento comum que um determinado valor de erro concreto pode implementar. Em seguida, com uma asserção de tipo genérica, você testa se esse comportamento existe e pode chamá-lo. A melhor parte é que você permanece em um estado desacoplado com o tratamento de erros.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eSempre Use a Interface de Erro\u003c/h2\u003e\n \n \n \u003cp\u003e\n Um erro que os desenvolvedores Go podem cometer é usar o tipo de erro concreto e não a interface de erro como o tipo de retorno para o tratamento de erros. Se você fizer isso, coisas ruins podem acontecer.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype customError struct{}\n\nfunc (c *customError) Error() string {\n return \u0026#34;Find the bug.\u0026#34;\n}\n\nfunc fail() ([]byte, *customError) {\n return nil, nil\n}\n\nfunc main() {\n var err error\n if _, err = fail(); err != nil {\n log.Fatal(\u0026#34;Why did this fail?\u0026#34;)\n }\n log.Println(\u0026#34;No Error\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eWhy did this fail?\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este código considera que há um erro quando a função \u003ccode\u003efail\u003c/code\u003e retorna \u003ccode\u003enil\u003c/code\u003e para o erro. Isso ocorre porque a função \u003ccode\u003efail\u003c/code\u003e está usando o tipo de erro concreto e não a interface de erro. Nesse caso, há um ponteiro \u003ccode\u003enil\u003c/code\u003e do tipo \u003ccode\u003ecustomError\u003c/code\u003e armazenado dentro da variável \u003ccode\u003eerr\u003c/code\u003e. Isso não é o mesmo que um valor de interface \u003ccode\u003enil\u003c/code\u003e do tipo \u003ccode\u003eerror\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eTratamento de Erros\u003c/h2\u003e\n \n \n \u003cp\u003e\n O tratamento de erros é mais uma conversa de engenharia em um nível macro. No meu mundo, o tratamento de erros significa que o erro para na função que está tratando o erro, o erro é registrado com contexto completo e o erro é verificado quanto à sua gravidade. Com base na gravidade e na capacidade de recuperação, é tomada uma decisão de recuperar, continuar ou encerrar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Um problema é que nem todas as funções podem lidar com um erro. Uma razão pode ser porque nem todas as funções estão autorizadas a registrar logs. O que acontece quando um erro está sendo passado de volta na pilha de chamadas e não pode ser tratado pela função que o recebe? Um erro precisa ser envolvido em contexto para que a função que eventualmente o trata possa fazê-lo corretamente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage main\n\nimport (\n \u0026#34;errors\u0026#34;\n \u0026#34;fmt\u0026#34;\n)\n\ntype AppError struct {\n State int\n}\n\nfunc (ae *AppError) Error() string {\n return fmt.Sprintf(\u0026#34;App Error, State: %d\u0026#34;, ae.State)\n}\n\nfunc IsAppError(err error) bool {\n var ae *AppError\n return errors.As(err, \u0026amp;ae)\n}\n\nfunc GetAppError(err error) *AppError {\n var ae *AppError\n if !errors.As(err, \u0026amp;ae) {\n return nil\n }\n return ae\n}\n\nfunc main() {\n if err := firstCall(10); err != nil {\n\n // Check if the error is an AppError.\n if IsAppError(err) {\n ae := GetAppError(err)\n fmt.Printf(\u0026#34;Is AppError, State: %d\\n\u0026#34;, ae.State)\n }\n\n fmt.Print(\u0026#34;\\n********************************\\n\\n\u0026#34;)\n\n // Display the error using the implementation of\n // the error interface.\n fmt.Printf(\u0026#34;%v\\n\u0026#34;, err)\n }\n}\n\nfunc firstCall(i int) error {\n if err := secondCall(i); err != nil {\n return fmt.Errorf(\u0026#34;secondCall(%d) : %w\u0026#34;, i, err)\n }\n return nil\n}\n\nfunc secondCall(i int) error {\n return \u0026amp;AppError{99}\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eIs AppError, State: 99\n\n********************************\n\nsecondCall(10) : App Error, State: 99\u003c/pre\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eUse o valor padrão de erro para mensagens estáticas e simplesmente formatadas.\u003c/li\u003e\n \n \u003cli\u003eCrie e retorne variáveis de erro para ajudar o \u003ccode\u003ecaller\u003c/code\u003e a identificar erros específicos.\u003c/li\u003e\n \n \u003cli\u003eCrie tipos de erro personalizados quando o contexto do erro for mais complexo.\u003c/li\u003e\n \n \u003cli\u003eOs valores de erro em Go não são especiais, são apenas valores como qualquer outro, e você tem toda a linguagem à sua disposição.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eCitações\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u0026#34;Os sistemas não podem ser desenvolvidos assumindo que os seres humanos serão capazes de escrever milhões de linhas de código sem cometer erros, e depurar sozinho não é uma maneira eficiente de desenvolver sistemas confiáveis.\u0026#34; - Al Aho (inventor do AWK)\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://go.dev/blog/error-handling-and-go\" target=\"_blank\"\u003eError handling and Go\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://go.dev/blog/go1.13-errors\" target=\"_blank\"\u003eWorking with Errors in Go 1.13\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/10/error-handling-in-go-part-i.html\" target=\"_blank\"\u003eError Handling In Go, Part I\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/11/error-handling-in-go-part-ii.html\" target=\"_blank\"\u003eError Handling In Go, Part II\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2017/05/design-philosophy-on-logging.html\" target=\"_blank\"\u003eDesign Philosophy On Logging\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://clipperhouse.com/bugs-are-a-failure-of-prediction/\" target=\"_blank\"\u003eBugs are a failure of prediction\u003c/a\u003e - Matt Sherman \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://dave.cheney.net/2014/12/24/inspecting-errors\" target=\"_blank\"\u003eInspecting errors\u003c/a\u003e - Dave Cheney \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully\" target=\"_blank\"\u003eDon’t just check errors, handle them gracefully\u003c/a\u003e - Dave Cheney \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://dave.cheney.net/2016/06/12/stack-traces-and-the-errors-package\" target=\"_blank\"\u003eStack traces and the errors package\u003c/a\u003e - Dave Cheney \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://commandcenter.blogspot.com/2017/12/error-handling-in-upspin.html\" target=\"_blank\"\u003eError handling in Upspin\u003c/a\u003e - Rob Pike \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://rauljordan.com/why-go-error-handling-is-awesome/\" target=\"_blank\"\u003eWhy Go\u0026#39;s Error Handling is Awesome\u003c/a\u003e - Raul Jordan\n\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how the default error type is implemented.\npackage main\n\nimport \"fmt\"\n\n// https://golang.org/pkg/builtin/#error\ntype error interface {\n\tError() string\n}\n\n// https://golang.org/src/pkg/errors/errors.go\ntype errorString struct {\n\ts string\n}\n\n// https://golang.org/src/pkg/errors/errors.go\nfunc (e *errorString) Error() string {\n\treturn e.s\n}\n\n// https://golang.org/src/pkg/errors/errors.go\n// New returns an error that formats as the given text.\nfunc New(text string) error {\n\treturn \u0026errorString{text}\n}\n\nfunc main() {\n\tif err := webCall(); err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"Life is good\")\n}\n\n// webCall performs a web operation.\nfunc webCall() error {\n\treturn New(\"Bad Request\")\n}\n","Hash":"YWVVJ3bcTxEqV86k2JIRM6Kt12g="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use error variables to help the\n// caller determine the exact error being returned.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\t// ErrBadRequest is returned when there are problems with the request.\n\tErrBadRequest = errors.New(\"Bad Request\")\n\n\t// ErrPageMoved is returned when a 301/302 is returned.\n\tErrPageMoved = errors.New(\"Page Moved\")\n)\n\nfunc main() {\n\tif err := webCall(true); err != nil {\n\t\tswitch err {\n\t\tcase ErrBadRequest:\n\t\t\tfmt.Println(\"Bad Request Occurred\")\n\t\t\treturn\n\n\t\tcase ErrPageMoved:\n\t\t\tfmt.Println(\"The Page moved\")\n\t\t\treturn\n\n\t\tdefault:\n\t\t\tfmt.Println(err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tfmt.Println(\"Life is good\")\n}\n\n// webCall performs a web operation.\nfunc webCall(b bool) error {\n\tif b {\n\t\treturn ErrBadRequest\n\t}\n\n\treturn ErrPageMoved\n}\n","Hash":"vMgc1oFtiUHnWAVz3kRycm+h3W4="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// https://golang.org/src/pkg/encoding/json/decode.go\n// Sample program to show how to implement a custom error type\n// based on the json package in the standard library.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\n// An UnmarshalTypeError describes a JSON value that was\n// not appropriate for a value of a specific Go type.\ntype UnmarshalTypeError struct {\n\tValue string // description of JSON value\n\tType reflect.Type // type of Go value it could not be assigned to\n}\n\n// Error implements the error interface.\nfunc (e *UnmarshalTypeError) Error() string {\n\treturn \"json: cannot unmarshal \" + e.Value + \" into Go value of type \" + e.Type.String()\n}\n\n// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.\n// (The argument to Unmarshal must be a non-nil pointer.)\ntype InvalidUnmarshalError struct {\n\tType reflect.Type\n}\n\n// Error implements the error interface.\nfunc (e *InvalidUnmarshalError) Error() string {\n\tif e.Type == nil {\n\t\treturn \"json: Unmarshal(nil)\"\n\t}\n\n\tif e.Type.Kind() != reflect.Ptr {\n\t\treturn \"json: Unmarshal(non-pointer \" + e.Type.String() + \")\"\n\t}\n\treturn \"json: Unmarshal(nil \" + e.Type.String() + \")\"\n}\n\n// user is a type for use in the Unmarshal call.\ntype user struct {\n\tName int\n}\n\nfunc main() {\n\tvar u user\n\terr := Unmarshal([]byte(`{\"name\":\"bill\"}`), u) // Run with a value and pointer.\n\tif err != nil {\n\t\tswitch e := err.(type) {\n\t\tcase *UnmarshalTypeError:\n\t\t\tfmt.Printf(\"UnmarshalTypeError: Value[%s] Type[%v]\\n\", e.Value, e.Type)\n\t\tcase *InvalidUnmarshalError:\n\t\t\tfmt.Printf(\"InvalidUnmarshalError: Type[%v]\\n\", e.Type)\n\t\tdefault:\n\t\t\tfmt.Println(err)\n\t\t}\n\t\treturn\n\t}\n\n\tfmt.Println(\"Name:\", u.Name)\n}\n\n// Unmarshal simulates an unmarshal call that always fails.\nfunc Unmarshal(data []byte, v interface{}) error {\n\trv := reflect.ValueOf(v)\n\tif rv.Kind() != reflect.Ptr || rv.IsNil() {\n\t\treturn \u0026InvalidUnmarshalError{reflect.TypeOf(v)}\n\t}\n\n\treturn \u0026UnmarshalTypeError{\"string\", reflect.TypeOf(v)}\n}\n","Hash":"gTCeM7VgJjcVhdvKgYZJ0cXj0nA="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Package example4 provides code to show how to implement behavior as context.\npackage example4\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n)\n\n// client represents a single connection in the room.\ntype client struct {\n\tname string\n\treader *bufio.Reader\n}\n\n// TypeAsContext shows how to check multiple types of possible custom error\n// types that can be returned from the net package.\nfunc (c *client) TypeAsContext() {\n\tfor {\n\t\tline, err := c.reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tswitch e := err.(type) {\n\t\t\tcase *net.OpError:\n\t\t\t\tif !e.Temporary() {\n\t\t\t\t\tlog.Println(\"Temporary: Client leaving chat\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tcase *net.AddrError:\n\t\t\t\tif !e.Temporary() {\n\t\t\t\t\tlog.Println(\"Temporary: Client leaving chat\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tcase *net.DNSConfigError:\n\t\t\t\tif !e.Temporary() {\n\t\t\t\t\tlog.Println(\"Temporary: Client leaving chat\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\tlog.Println(\"EOF: Client leaving chat\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlog.Println(\"read-routine\", err)\n\t\t\t}\n\t\t}\n\n\t\tfmt.Println(line)\n\t}\n}\n\n// temporary is declared to test for the existence of the method coming\n// from the net package.\ntype temporary interface {\n\tTemporary() bool\n}\n\n// BehaviorAsContext shows how to check for the behavior of an interface\n// that can be returned from the net package.\nfunc (c *client) BehaviorAsContext() {\n\tfor {\n\t\tline, err := c.reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tswitch e := err.(type) {\n\t\t\tcase temporary:\n\t\t\t\tif !e.Temporary() {\n\t\t\t\t\tlog.Println(\"Temporary: Client leaving chat\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\tlog.Println(\"EOF: Client leaving chat\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlog.Println(\"read-routine\", err)\n\t\t\t}\n\t\t}\n\n\t\tfmt.Println(line)\n\t}\n}\n","Hash":"E6KKDilyBzpvahisdxM4fgQL1nM="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show see if the class can find the bug.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n)\n\n// customError is just an empty struct.\ntype customError struct{}\n\n// Error implements the error interface.\nfunc (c *customError) Error() string {\n\treturn \"Find the bug.\"\n}\n\n// fail returns nil values for both return types.\nfunc fail() ([]byte, *customError) {\n\treturn nil, nil\n}\n\nfunc main() {\n\tvar err error\n\tif _, err = fail(); err != nil {\n\t\tlog.Fatal(\"Why did this fail?\")\n\t}\n\n\tlog.Println(\"No Error\")\n}\n\n// =============================================================================\n\nfunc reason() {\n\tvar err error\n\tfmt.Printf(\"Type of value stored inside the interface: %T\\n\", err)\n\n\tif _, err = fail(); err != nil {\n\t\tfmt.Printf(\"Type of value stored inside the interface: %T\\n\", err)\n\t}\n\n\tlog.Println(\"No Error\")\n}\n","Hash":"RPJ/ZXi2qObi8t3eWTdbym0XkMs="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how wrapping errors work with the stdlib.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// AppError represents a custom error type.\ntype AppError struct {\n\tState int\n}\n\n// Error implements the error interface.\nfunc (ae *AppError) Error() string {\n\treturn fmt.Sprintf(\"App Error, State: %d\", ae.State)\n}\n\n// IsAppError checks if an error of type AppError exists.\nfunc IsAppError(err error) bool {\n\tvar ae *AppError\n\treturn errors.As(err, \u0026ae)\n}\n\n// GetAppError returns a copy of the AppError pointer.\nfunc GetAppError(err error) *AppError {\n\tvar ae *AppError\n\tif !errors.As(err, \u0026ae) {\n\t\treturn nil\n\t}\n\treturn ae\n}\n\nfunc main() {\n\n\t// Make the function call and validate the error.\n\tif err := firstCall(10); err != nil {\n\n\t\t// Check if the error is an AppError.\n\t\tif IsAppError(err) {\n\t\t\tae := GetAppError(err)\n\t\t\tfmt.Printf(\"Is AppError, State: %d\\n\", ae.State)\n\t\t}\n\n\t\tfmt.Print(\"\\n********************************\\n\\n\")\n\n\t\t// Display the error using the implementation of\n\t\t// the error interface.\n\t\tfmt.Printf(\"%v\\n\", err)\n\t}\n}\n\n// firstCall makes a call to a second function and wraps any error.\nfunc firstCall(i int) error {\n\tif err := secondCall(i); err != nil {\n\t\treturn fmt.Errorf(\"firstCall-\u003esecondCall(%d) : %w\", i, err)\n\t}\n\treturn nil\n}\n\n// secondCall makes a call to a third function and wraps any error.\nfunc secondCall(i int) error {\n\tif err := thirdCall(); err != nil {\n\t\treturn fmt.Errorf(\"secondCall-\u003ethirdCall() : %w\", err)\n\t}\n\treturn nil\n}\n\n// thirdCall create an error value we will validate.\nfunc thirdCall() error {\n\treturn \u0026AppError{99}\n}\n","Hash":"NmYPKjFSZ+VyuZ4etLuILj6y7f0="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Crie duas variáveis de erro, uma chamada \u003ccode\u003eErrInvalidValue\u003c/code\u003e e a outra chamada \u003ccode\u003eErrAmountTooLarge\u003c/code\u003e. Forneça a mensagem estática para cada variável. Em seguida, escreva uma função chamada \u003ccode\u003echeckAmount\u003c/code\u003e que aceita um valor do tipo \u003ccode\u003efloat64\u003c/code\u003e e retorna um valor de erro. Verifique se o valor é zero e, se for, retorne \u003ccode\u003eErrInvalidValue\u003c/code\u003e. Verifique se o valor é maior que $1.000 e, se for, retorne \u003ccode\u003eErrAmountTooLarge\u003c/code\u003e. Escreva uma função principal para chamar a função \u003ccode\u003echeckAmount\u003c/code\u003e e verificar o valor de erro retornado. Exiba uma mensagem apropriada na tela.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExercício 2\u003c/h2\u003e\n \n \n \u003cp\u003e\n Crie um tipo de erro personalizado chamado \u003ccode\u003eappError\u003c/code\u003e que contenha três campos: \u003ccode\u003eerr\u003c/code\u003e do tipo \u003ccode\u003eerror\u003c/code\u003e, \u003ccode\u003emessage\u003c/code\u003e do tipo \u003ccode\u003estring\u003c/code\u003e e \u003ccode\u003ecode\u003c/code\u003e do tipo \u003ccode\u003eint\u003c/code\u003e. Implemente a interface de erro (\u003ccode\u003eerror\u003c/code\u003e) fornecendo sua própria mensagem usando esses três campos. Implemente um segundo método chamado \u003ccode\u003etemporary\u003c/code\u003e que retorne \u003ccode\u003efalse\u003c/code\u003e quando o valor do campo \u003ccode\u003ecode\u003c/code\u003e for igual a 9. Escreva uma função chamada \u003ccode\u003echeckFlag\u003c/code\u003e que aceita um valor booleano. Se o valor for \u003ccode\u003efalse\u003c/code\u003e, retorne um ponteiro para o seu tipo de erro personalizado inicializado como desejar. Se o valor for \u003ccode\u003etrue\u003c/code\u003e, retorne um erro padrão. Escreva uma função principal para chamar a função \u003ccode\u003echeckFlag\u003c/code\u003e e verificar o erro usando a interface \u003ccode\u003etemporary\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create two error variables, one called ErrInvalidValue and the other\n// called ErrAmountTooLarge. Provide the static message for each variable.\n// Then write a function called checkAmount that accepts a float64 type value\n// and returns an error value. Check the value for zero and if it is, return\n// the ErrInvalidValue. Check the value for greater than $1,000 and if it is,\n// return the ErrAmountTooLarge. Write a main function to call the checkAmount\n// function and check the return error value. Display a proper message to the screen.\npackage main\n\n// Add imports.\n\nvar (\n// Declare an error variable named ErrInvalidValue using the New\n// function from the errors package.\n\n// Declare an error variable named ErrAmountTooLarge using the New\n// function from the errors package.\n)\n\n// Declare a function named checkAmount that accepts a value of\n// type float64 and returns an error interface value.\nfunc checkAmount( /* parameter */ ) /* return arg */ {\n\n\t// Is the parameter equal to zero. If so then return\n\t// the error variable.\n\n\t// Is the parameter greater than 1000. If so then return\n\t// the other error variable.\n\n\t// Return nil for the error value.\n}\n\nfunc main() {\n\n\t// Call the checkAmount function and check the error. Then\n\t// use a switch/case to compare the error with each variable.\n\t// Add a default case. Return if there is an error.\n\n\t// Display everything is good.\n}\n","Hash":"lnCpc4ldvg5/RdGV69+ixjFgEEo="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create two error variables, one called ErrInvalidValue and the other\n// called ErrAmountTooLarge. Provide the static message for each variable.\n// Then write a function called checkAmount that accepts a float64 type value\n// and returns an error value. Check the value for zero and if it is, return\n// the ErrInvalidValue. Check the value for greater than $1,000 and if it is,\n// return the ErrAmountTooLarge. Write a main function to call the checkAmount\n// function and check the return error value. Display a proper message to the screen.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\t// ErrInvalidValue indicates the value is invalid.\n\tErrInvalidValue = errors.New(\"Invalid Value\")\n\n\t// ErrAmountTooLarge indicates the value beyond the upper bound.\n\tErrAmountTooLarge = errors.New(\"Amount To Large\")\n)\n\nfunc main() {\n\n\t// Call the function and get the error.\n\tif err := checkAmount(0); err != nil {\n\t\tswitch err {\n\n\t\t// Check if the error is an ErrInvalidValue.\n\t\tcase ErrInvalidValue:\n\t\t\tfmt.Println(\"Value provided is not valid.\")\n\t\t\treturn\n\n\t\t// Check if the error is an ErrAmountTooLarge.\n\t\tcase ErrAmountTooLarge:\n\t\t\tfmt.Println(\"Value provided is too large.\")\n\t\t\treturn\n\n\t\t// Handle the default error.\n\t\tdefault:\n\t\t\tfmt.Println(err)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Display everything is good.\n\tfmt.Println(\"Everything checks out.\")\n}\n\n// checkAmount validates the value passed in.\nfunc checkAmount(f float64) error {\n\tswitch {\n\n\t// Is the parameter equal to zero.\n\tcase f == 0:\n\t\treturn ErrInvalidValue\n\n\t// Is the parameter greater than 1000.\n\tcase f \u003e 1000:\n\t\treturn ErrAmountTooLarge\n\t}\n\n\treturn nil\n}\n","Hash":"oycX2nlCesN9faFTEHHQKTRskXo="},{"Name":"exercise2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create a custom error type called appError that contains three fields, err error,\n// message string and code int. Implement the error interface providing your own message\n// using these three fields. Implement a second method named temporary that returns false\n// when the value of the code field is 9. Write a function called checkFlag that accepts\n// a bool value. If the value is false, return a pointer of your custom error type\n// initialized as you like. If the value is true, return a default error. Write a main\n// function to call the checkFlag function and check the error using the temporary\n// interface.\npackage main\n\n// Add imports.\n\n// Declare a struct type named appError with three fields, err of type error,\n// message of type string and code of type int.\n\n// Declare a method for the appError struct type that implements the\n// error interface.\n\n// Declare a method for the appError struct type named Temporary that returns\n// true when the value of the code field is not 9.\n\n// Declare the temporary interface type with a method named Temporary that\n// takes no parameters and returns a bool.\n\n// Declare a function named checkFlag that accepts a boolean value and\n// returns an error interface value.\nfunc checkFlag( /* parameter */ ) /* return arg */ {\n\n\t// If the parameter is false return an appError.\n\n\t// Return a default error.\n}\n\nfunc main() {\n\n\t// Call the checkFlag function to simulate an error of the\n\t// concrete type.\n\n\t// Check the concrete type and handle appropriately.\n\tswitch e := err.(type) {\n\n\t// Apply the case for the existence of the Temporary behavior.\n\t// Log the error and write a second message only if the\n\t// error is not temporary.\n\n\t// Apply the default case and just log the error.\n\t}\n}\n","Hash":"dTgHxE/SAJevPrfzegzAoxFgcHA="},{"Name":"answer2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Create a custom error type called appError that contains three fields, err error,\n// message string and code int. Implement the error interface providing your own message\n// using these three fields. Implement a second method named temporary that returns false\n// when the value of the code field is 9. Write a function called checkFlag that accepts\n// a bool value. If the value is false, return a pointer of your custom error type\n// initialized as you like. If the value is true, return a default error. Write a main\n// function to call the checkFlag function and check the error using the temporary\n// interface.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// appError is a custom error type for the program.\ntype appError struct {\n\terr error\n\tmessage string\n\tcode int\n}\n\n// Error implements the error interface for appError.\nfunc (a *appError) Error() string {\n\treturn fmt.Sprintf(\"App Error[%s] Message[%s] Code[%d]\", a.err, a.message, a.code)\n}\n\n// Temporary implements behavior about the error.\nfunc (a *appError) Temporary() bool {\n\treturn (a.code != 9)\n}\n\n// temporary is used to test the error we receive.\ntype temporary interface {\n\tTemporary() bool\n}\n\nfunc main() {\n\tif err := checkFlag(false); err != nil {\n\t\tswitch e := err.(type) {\n\t\tcase temporary:\n\t\t\tfmt.Println(err)\n\t\t\tif !e.Temporary() {\n\t\t\t\tfmt.Println(\"Critical Error!\")\n\t\t\t}\n\t\tdefault:\n\t\t\tfmt.Println(err)\n\t\t}\n\t}\n}\n\n// checkFlag returns one of two errors based on the value of the parameter.\nfunc checkFlag(t bool) error {\n\n\t// If the parameter is false return an appError.\n\tif !t {\n\t\treturn \u0026appError{errors.New(\"Flag False\"), \"The Flag was false\", 9}\n\t}\n\n\t// Return a default error.\n\treturn errors.New(\"Flag True\")\n}\n","Hash":"EC+6G7XEZZxtAU6BCrvFTtYSRuw="}]}]} ,"generics-underlying-types":{"Title":"Tipos Subjacents","Description":"Você pode declarar um tipo genérico usando um tipo subjacente.","Pages":[{"Title":"Generics - Underlying Types","Content":"\n \u003ch2\u003eGenerics - Underlying Types\u003c/h2\u003e\n \n \n \u003cp\u003e\n Você pode declarar um tipo genérico usando um tipo subjacente.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre \u003ccode\u003eGenerics\u003c/code\u003e, que o guiará por todos os exemplos desta seção do Tour.\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Tipo de vetor concreto\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2\u003c/b\u003e: Tipo de vetor de interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3\u003c/b\u003e: Tipo de vetor genérico\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicação\u003c/h2\u003e\n \n \n \u003cp\u003e\n E se você quisesse declarar seu próprio tipo genérico usando um tipo subjacente?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype vector[T any] []T\n\nfunc (v vector[T]) last() (T, error) {\n var zero T\n \n if len(v) == 0 {\n return zero, errors.New(\u0026#34;empty\u0026#34;)\n }\n \n return v[len(v)-1], nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este exemplo mostra um tipo genérico de vetor que restringe a construção de um vetor\n\n\n a um único tipo de dado. O uso de colchetes quadrados declara que o tipo T é um tipo genérico\n\n\n a ser determinado em tempo de compilação. O uso da restrição \u003ccode\u003eany\u003c/code\u003e descreve que não há restrição \n\n\n sobre o que o tipo T pode se tornar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O último método é declarado com um receptor de valor do tipo vetor[T] para representar um valor\n\n\n do tipo vetor com uma fatia subjacente de algum tipo T. O método retorna um valor desse mesmo tipo T.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n fmt.Print(\u0026#34;vector[int] : \u0026#34;)\n\n vGenInt := vector[int]{10, -1}\n\n i, err := vGenInt.last()\n if err != nil {\n fmt.Print(\u0026#34;ERROR:\u0026#34;, err)\n return\n }\n\n if i \u0026lt; 0 {\n fmt.Print(\u0026#34;negative integer: \u0026#34;)\n }\n\n fmt.Printf(\u0026#34;value: %d\\n\u0026#34;, i)\n\n // -------------------------------------------------------------------------\n\n fmt.Print(\u0026#34;vector[string] : \u0026#34;)\n\n vGenStr := vector[string]{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, string([]byte{0xff})}\n\n s, err := vGenStr.last()\n if err != nil {\n fmt.Print(\u0026#34;ERROR:\u0026#34;, err)\n return\n }\n\n if !utf8.ValidString(s) {\n fmt.Print(\u0026#34;non-valid string: \u0026#34;)\n }\n\n fmt.Printf(\u0026#34;value: %q\\n\u0026#34;, s)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evector[int] : número inteiro negativo: valor: -1\nvector[string] : sequência de caracteres inválida: valor: \u0026#34;\\xff\u0026#34;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Isso é como construir um valor do tipo vector com um tipo subjacente de int quando eu vou\n\n\n definir valores no vetor na construção. Um aspecto importante deste código são as chamadas de construção.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// Zero Value Construction\nvar vGenInt vector[int]\nvar vGenStr vector[string]\n\n// Non-Zero Value Construction\nvGenInt := vector{10, -1}\nvGenStr := vector{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, string([]byte{0xff})}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando se trata de construir esses tipos genéricos até o valor zero, não é possível para o\n\n\n compilador inferir o tipo. No entanto, em casos em que há inicialização durante a construção,\n\n\n o compilador pode inferir o tipo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Existe um aspecto da especificação que se concentra na construção de um tipo genérico\n\n\n até seu estado de zero value.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype vector[T any] []T\n\nfunc (v vector[T]) last() (T, error) {\n var zero T\n \n if len(v) == 0 {\n return zero, errors.New(\u0026#34;empty\u0026#34;)\n }\n \n return v[len(v)-1], nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você precisa se concentrar na declaração do método para o último método e como o método retorna um valor\n\n\n do tipo genérico T. No primeiro retorno, é uma situação em que você precisa retornar o valor zero para o tipo T.\n\n\n A implementação atual fornece duas soluções para escrever este código. A primeira solução que você já viu.\n\n\n Uma variável chamada \u0026#34;zero\u0026#34; é construída em seu estado de valor zero do tipo T e, em seguida, essa variável\n\n\n é usada para o retorno.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A outra opção é usar a função built-in \u003ccode\u003enew\u003c/code\u003e e desreferenciar o ponteiro retornado na declaração de retorno.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype vector[T any] []T\n\nfunc (v vector[T]) last() (T, error) {\n if len(v) == 0 {\n return *new(T), errors.New(\u0026#34;empty\u0026#34;)\n }\n \n return v[len(v)-1], nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Essa versão do último método está usando a função built-in \u003ccode\u003enew\u003c/code\u003e para a construção\n\n\n do `zero value` e a desreferenciação do ponteiro retornado para satisfazer o tipo de retorno T.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Observação: Você pode se perguntar por que não usar \u003ccode\u003eT{}\u003c/code\u003e para realizar a construção do `zero value`?\n\n\n O problema é que essa sintaxe não funciona com todos os tipos, como os tipos escalares (int, string, bool).\n\n\n Portanto, não é uma opção.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare two user defined types based on an\n// underlying concrete type. Each type implements a method named last that\n// returns the value stored at the highest index position in the vector or an\n// error when the vector is empty.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"unicode/utf8\"\n)\n\ntype vectorInt []int\n\nfunc (v vectorInt) last() (int, error) {\n\tif len(v) == 0 {\n\t\treturn 0, errors.New(\"empty\")\n\t}\n\n\treturn v[len(v)-1], nil\n}\n\n// =============================================================================\n\ntype vectorString []string\n\nfunc (v vectorString) last() (string, error) {\n\tif len(v) == 0 {\n\t\treturn \"\", errors.New(\"empty\")\n\t}\n\n\treturn v[len(v)-1], nil\n}\n\n// =============================================================================\n\nfunc main() {\n\tfmt.Print(\"vectorInt : \")\n\n\tvInt := vectorInt{10, -1}\n\n\ti, err := vInt.last()\n\tif err != nil {\n\t\tfmt.Print(\"ERROR:\", err)\n\t\treturn\n\t}\n\n\tif i \u003c 0 {\n\t\tfmt.Print(\"negative integer: \")\n\t}\n\n\tfmt.Printf(\"value: %d\\n\", i)\n\n\t// -------------------------------------------------------------------------\n\n\tfmt.Print(\"vectorString : \")\n\n\tvStr := vectorString{\"A\", \"B\", string([]byte{0xff})}\n\n\ts, err := vStr.last()\n\tif err != nil {\n\t\tfmt.Print(\"ERROR:\", err)\n\t\treturn\n\t}\n\n\tif !utf8.ValidString(s) {\n\t\tfmt.Print(\"non-valid string: \")\n\t}\n\n\tfmt.Printf(\"value: %q\\n\", s)\n}\n","Hash":"2uShryLQLosC7Jq6SH/TLp5a/gw="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare a type that is based on the empty\n// interface so any value can be added into the vector. Since the last\n// function is using the empty interface for the return, users will need to\n// perform type assertions to get back to the concrete value being stored\n// inside the interface.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"unicode/utf8\"\n)\n\ntype vectorInterface []interface{}\n\nfunc (v vectorInterface) last() (interface{}, error) {\n\tif len(v) == 0 {\n\t\treturn nil, errors.New(\"empty\")\n\t}\n\n\treturn v[len(v)-1], nil\n}\n\n// =============================================================================\n\nfunc main() {\n\tfmt.Print(\"vectorInterface : \")\n\n\tvItf := vectorInterface{10, \"A\", 20, \"B\", 3.14}\n\n\titf, err := vItf.last()\n\tif err != nil {\n\t\tfmt.Print(\"ERROR:\", err)\n\t\treturn\n\t}\n\n\tswitch v := itf.(type) {\n\tcase int:\n\t\tif v \u003c 0 {\n\t\t\tfmt.Print(\"negative integer: \")\n\t\t}\n\tcase string:\n\t\tif !utf8.ValidString(v) {\n\t\t\tfmt.Print(\"non-valid string: \")\n\t\t}\n\tdefault:\n\t\tfmt.Printf(\"unknown type %T: \", v)\n\t}\n\n\tfmt.Printf(\"value: %v\\n\", itf)\n}\n","Hash":"2yGqZsJHshnZWQj5McUCkDGaQPg="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare a generics version of the user defined\n// type. It represents a slice of some type T (to be determined later). The\n// last method is declared with a value receiver based on a vector of the\n// same type T and returns a value of that same type T as well.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"unicode/utf8\"\n)\n\ntype vector[T any] []T\n\nfunc (v vector[T]) last() (T, error) {\n\tvar zero T\n\n\tif len(v) == 0 {\n\t\treturn zero, errors.New(\"empty\")\n\t}\n\n\treturn v[len(v)-1], nil\n}\n\n// =============================================================================\n\nfunc main() {\n\tfmt.Print(\"vector[int] : \")\n\n\tvGenInt := vector[int]{10, -1}\n\n\ti, err := vGenInt.last()\n\tif err != nil {\n\t\tfmt.Print(\"ERROR:\", err)\n\t\treturn\n\t}\n\n\tif i \u003c 0 {\n\t\tfmt.Print(\"negative integer: \")\n\t}\n\n\tfmt.Printf(\"value: %d\\n\", i)\n\n\t// -------------------------------------------------------------------------\n\n\tfmt.Print(\"vector[string] : \")\n\n\tvGenStr := vector[string]{\"A\", \"B\", string([]byte{0xff})}\n\n\ts, err := vGenStr.last()\n\tif err != nil {\n\t\tfmt.Print(\"ERROR:\", err)\n\t\treturn\n\t}\n\n\tif !utf8.ValidString(s) {\n\t\tfmt.Print(\"non-valid string: \")\n\t}\n\n\tfmt.Printf(\"value: %q\\n\", s)\n}\n","Hash":"IUvCjlqWarCTxdpSBw3mdX6HHyI="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para concluir os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declare um tipo genérico chamado \u003ccode\u003ekeymap\u003c/code\u003e que utiliza um tipo subjacente de \u003ccode\u003emap\u003c/code\u003e com uma chave do\n\n\n tipo \u003ccode\u003estring\u003c/code\u003e e um valor de algum tipo \u003ccode\u003eT\u003c/code\u003e. Declare um método chamado \u003ccode\u003eset\u003c/code\u003e que aceita uma chave do tipo\n\n\n \u003ccode\u003estring\u003c/code\u003e e um valor do tipo \u003ccode\u003eT\u003c/code\u003e. Declare um método chamado \u003ccode\u003eget\u003c/code\u003e que aceita uma chave do tipo \u003ccode\u003estring\u003c/code\u003e e\n\n\n retorna um valor do tipo \u003ccode\u003eT\u003c/code\u003e e \u003ccode\u003etrue\u003c/code\u003e ou \u003ccode\u003efalse\u003c/code\u003e se a chave for encontrada. Em seguida, escreva uma função\n\n\n \u003ccode\u003emain\u003c/code\u003e que utilize os métodos.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic map type.\npackage main\n\n// Declare a generic type named keymap that uses an underlying type of map\n// with a key of type string and a value of some type T.\n\n// Implement a method named set that accepts a key of type string and a value\n// of type T.\n\n// Implement a method named get that accepts a key of type string and return\n// a value of type T and true or false if the key is found.\n\nfunc main() {\n\t// Construct a value of type keymap that stores integers.\n\n\t// Add a value with key \"jack\" and a value of 10.\n\n\t// Add a value with key \"jill\" and a value of 20.\n\n\t// Get the value for \"jack\" and verify it's found.\n\n\t// Print the value for the key \"jack\".\n\n\t// Get the value for \"jill\" and verify it's found.\n\n\t// Print the value for the key \"jill\".\n}\n","Hash":"+ApONji/Jtk4ZT5k/8yXAlbmFVQ="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic map type.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n// Declare a generic type named keymap that uses an underlying type of map\n// with a key of type string and a value of some type T.\ntype keymap[T any] map[string]T\n\n// Implement a method named set that accepts a key of type string and a value\n// of type T.\nfunc (km keymap[T]) set(k string, v T) {\n\tkm[k] = v\n}\n\n// Implement a method named get that accepts a key of type string and return\n// a value of type T and true or false if the key is found.\nfunc (km keymap[T]) get(k string) (T, bool) {\n\tvar zero T\n\n\tv, found := km[k]\n\tif !found {\n\t\treturn zero, false\n\t}\n\n\treturn v, true\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Construct a value of type keymap that stores integers.\n\tkm := make(keymap[int])\n\n\t// Add a value with key \"jack\" and a value of 10.\n\tkm.set(\"jack\", 10)\n\n\t// Add a value with key \"jill\" and a value of 20.\n\tkm.set(\"jill\", 20)\n\n\t// Get the value for \"jack\" and verify it's found.\n\tjack, found := km.get(\"jack\")\n\tif !found {\n\t\tfmt.Println(\"jack not found\")\n\t\treturn\n\t}\n\n\t// Print the value for the key \"jack\".\n\tfmt.Println(\"jack\", jack)\n\n\t// Get the value for \"jill\" and verify it's found.\n\tjill, found := km.get(\"jill\")\n\tif !found {\n\t\tfmt.Println(\"jill not found\")\n\t\treturn\n\t}\n\n\t// Print the value for the key \"jill\".\n\tfmt.Println(\"jill\", jill)\n}\n","Hash":"J5EvbYv9OgCxkHAP0uuGvKLCQS8="}]}]} ,"slices":{"Title":"Slices","Description":"`Slices` são uma estrutura de dados incrivelmente importante em Go. Elas formam a base de como gerenciamos e manipulamos dados de forma flexível, eficiente e dinâmica. É muito benéfico para todos os programadores em Go aprenderem como `Slices` funcionam e como usá-los.","Pages":[{"Title":"Slices","Content":"\n \u003ch2\u003eSlices\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use a Nossa \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003ccode\u003eSlices\u003c/code\u003e são uma estrutura de dados incrivelmente importante em Go. Elas formam a base de como gerenciamos e manipulamos dados de forma flexível, eficiente e dinâmica. É muito benéfico para todos os programadores em Go aprenderem como \u003ccode\u003eSlices\u003c/code\u003e funcionam e como usá-los.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl1.png\"\u003e\n \u003c/a\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declarar e Obter o comprimento\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Tipos por Referência\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Anexando slices\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Obter slices de slices\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Slices e Referências\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e Strings e slices\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e7:\u003c/b\u003e Funções Variádicas\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e8:\u003c/b\u003e Mecânica do Range\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e9:\u003c/b\u003e Travessias Eficientes\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e10:\u003c/b\u003e Slicing com Três Índices\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eConstrução de Slice\u003c/h2\u003e\n \n \n \u003cp\u003e\n A construção de uma slice pode ser feita de várias maneiras.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// Slice of string set to its zero value state.\nvar slice []string\n\n// Slice of string set to its empty state.\nslice := []string{}\n\n// Slice of string set with a length and capacity of 5.\nslice := make([]string, 5)\n\n// Slice of string set with a length of 5 and capacity of 8.\nslice := make([]string, 5, 8)\n\n// Slice of string set with values with a length and capacity of 5.\nslice := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver que a função embutida make me permite alocar previamente tanto o comprimento\n\n\n quanto a capacidade para o \u003ccode\u003earray\u003c/code\u003e subjacente. Se o compilador conhece o tamanho em tempo de\n\n\n compilação, o \u003ccode\u003earray\u003c/code\u003e subjacente pode ser construído na pilha.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eSlice: Comprimento vs Capacidade\u003c/h2\u003e\n \n \n \u003cp\u003e\n O comprimento de um \u003ccode\u003eSlice\u003c/code\u003e representa o número de elementos que podem ser lidos e escritos.\n\n\n A capacidade representa o número total de elementos que existem no array subjacente a partir da posição do ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Devido a sintaxe, slices têm a aparência e a sensação de um \u003ccode\u003earray\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice := make([]string, 5)\nslice[0] = \u0026#34;Apple\u0026#34;\nslice[1] = \u0026#34;Orange\u0026#34;\nslice[2] = \u0026#34;Banana\u0026#34;\nslice[3] = \u0026#34;Grape\u0026#34;\nslice[4] = \u0026#34;Plum\u0026#34;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode distinguir entre a construção de um \u003ccode\u003eslice\u003c/code\u003e e a de um \u003ccode\u003earray\u003c/code\u003e, pois um \u003ccode\u003earray\u003c/code\u003e possui um tamanho\n\n\n conhecido em tempo de compilação, enquanto os \u003ccode\u003eslices\u003c/code\u003e não têm necessariamente essa informação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se você tentar acessar um elemento além do comprimento do slice, você receberá um erro em tempo de execução.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice := make([]string, 5)\nslice[5] = \u0026#34;Raspberry\u0026#34;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Erro de Compilador:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eError: panic: runtime error: index out of range slice[5] = \u0026#34;Runtime error\u0026#34;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste exemplo, o comprimento do \u003ccode\u003eslice\u003c/code\u003e é 5 e estou tentando acessar o sexto elemento, que não existe.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eDiretriz Semântica de Dados para `Slices`\u003c/h2\u003e\n \n \n \u003cp\u003e\n Como diretriz, se os dados com os quais estou trabalhando são um \u003ccode\u003eslice\u003c/code\u003e, então use a\n\n\n semântica de valor para mover os dados ao redor do meu programa. Isso inclui declarar campos em um tipo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Foo(data []byte) []byte\n\ntype Foo struct {\n X []int\n Y []string\n Z []bool\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Isso se aplica a todas as estruturas de dados internas do Go (slices, maps, channels, interfaces e functions).\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Uma razão para mudar para a semântica de ponteiro é se você precisar compartilhar o \u003ccode\u003eslice\u003c/code\u003e para uma operação\n\n\n de `decoding ou unmarshal`. Usar ponteiros para esses tipos de operações é aceitável, mas documente\n\n\n isso se não for óbvio.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eLayout de Memória Contígua\u003c/h2\u003e\n \n \n \u003cp\u003e\n A ideia por trás do \u003ccode\u003eslice\u003c/code\u003e é ter um \u003ccode\u003earray\u003c/code\u003e, que é a estrutura de dados mais eficiente em\n\n\n relação ao hardware. No entanto, ainda é necessário ter a capacidade de ser dinâmico e\n\n\n eficiente com a quantidade de dados necessária em tempo de execução e crescimento futuro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n slice := make([]string, 5, 8)\n slice[0] = \u0026#34;Apple\u0026#34;\n slice[1] = \u0026#34;Orange\u0026#34;\n slice[2] = \u0026#34;Banana\u0026#34;\n slice[3] = \u0026#34;Grape\u0026#34;\n slice[4] = \u0026#34;Plum\u0026#34;\n\n inspectSlice(slice)\n}\n\nfunc inspectSlice(slice []string) {\n fmt.Printf(\u0026#34;Length[%d] Capacity[%d]\\n\u0026#34;, len(slice), cap(slice))\n for i := range slice {\n fmt.Printf(\u0026#34;[%d] %p %s\\n\u0026#34;, i, \u0026amp;slice[i], slice[i])\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eLength[5] Capacity[8]\n[0] 0xc00007e000 Apple\n[1] 0xc00007e010 Orange\n[2] 0xc00007e020 Banana\n[3] 0xc00007e030 Grape\n[4] 0xc00007e040 Plum\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função \u003ccode\u003einspectSlice\u003c/code\u003e mostra como um \u003ccode\u003eslice\u003c/code\u003e tem um \u003ccode\u003earray\u003c/code\u003e subjacente contíguo com um passo previsível.\n\n\n Também mostra como um \u003ccode\u003eslice\u003c/code\u003e tem um comprimento e uma capacidade que podem ser diferentes.\n\n\n Observe como a função print itera apenas sobre o comprimento do \u003ccode\u003eslice\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eAnexando Slices\u003c/h2\u003e\n \n \n \u003cp\u003e\n A linguagem fornece uma função built-in chamada append para adicionar valores a um slice existente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar data []string\n\nfor record := 1; record \u0026lt;= 102400; record\u0026#43;\u0026#43; {\n data = append(data, fmt.Sprintf(\u0026#34;Rec: %d\u0026#34;, record))\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função \u003ccode\u003eappend\u003c/code\u003e funciona com um \u003ccode\u003eslice\u003c/code\u003e mesmo quando o \u003ccode\u003eslice\u003c/code\u003e é inicializado no seu\n\n\n estado de `zero value`. O design da API do append é interessante porque utiliza a mutação\n\n\n semântica de valor. O append obtém sua própria cópia de um valor do \u003ccode\u003eslice\u003c/code\u003e, realiza a mutação\n\n\n em sua própria cópia e, em seguida, retorna uma cópia de volta para o chamador.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Por que a API é projetada dessa forma? Isso ocorre porque o idioma é usar semântica de valor para mover\n\n\n um valor de \u003ccode\u003eslice\u003c/code\u003e ao redor de um programa. Isso deve ser respeitado mesmo com uma operação de mutação.\n\n\n Além disso, a mutação semântica de valor é a maneira mais segura de realizar a mutação, uma vez que a\n\n\n mutação é realizada na própria cópia dos dados da função, isoladamente.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Append sempre mantém um bloco contíguo de memória para o array subjacente da \u003ccode\u003eslice\u003c/code\u003e, mesmo após o crescimento.\n\n\n Isso é importante para o hardware.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl2.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl2.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Sempre que a função \u003ccode\u003eappend\u003c/code\u003e é chamada, a função verifica se o comprimento e a capacidade do \u003ccode\u003eslice\u003c/code\u003e são\n\n\n iguais ou não. Se forem iguais, significa que não há mais espaço no \u003ccode\u003earray\u003c/code\u003e subjacente para o novo valor.\n\n\n Nesse caso, o \u003ccode\u003eappend\u003c/code\u003e cria um novo \u003ccode\u003earray\u003c/code\u003e subjacente (duplicando ou crescendo em 25%) e depois copia os\n\n\n valores do \u003ccode\u003earray\u003c/code\u003e antigo para o novo. Em seguida, o novo valor pode ser adicionado.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl3.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl3.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Se os comprimentos e capacidades não forem iguais, isso significa que há uma capacidade extra disponível\n\n\n para a operação de anexação. Um elemento é retirado da capacidade e adicionado ao comprimento do \u003ccode\u003eslice\u003c/code\u003e.\n\n\n Isso torna a operação de anexação muito eficiente.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando o \u003ccode\u003earray\u003c/code\u003e subjacente tem 1024 elementos de capacidade ou menos, novos \u003ccode\u003earrays\u003c/code\u003e subjacentes são construídos\n\n\n dobrando o tamanho do \u003ccode\u003earray\u003c/code\u003e existente. Uma vez que o \u003ccode\u003earray\u003c/code\u003e subjacente cresce além de 1024 elementos,\n\n\n o crescimento ocorre em 25%.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eNOTA:\u003c/b\u003e \u003cb\u003eA\u003c/b\u003e *forma \u003cb\u003eque\u003c/b\u003e \u003cb\u003efunção\u003c/b\u003e \u003cb\u003eappend\u003c/b\u003e \u003cb\u003eaumenta\u003c/b\u003e \u003cb\u003ea\u003c/b\u003e \u003cb\u003ecapacidade\u003c/b\u003e \u003cb\u003edo\u003c/b\u003e \u003cb\u003earray\u003c/b\u003e\n\n\n \u003cb\u003esubjacente\u003c/b\u003e \u003cb\u003emudou\u003c/b\u003e \u003cb\u003edesde\u003c/b\u003e \u003cb\u003eGo\u003c/b\u003e \u003cb\u003e1.18.\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://tip.golang.org/doc/go1.18#runtime\" target=\"_blank\"\u003ehttps://tip.golang.org/doc/go1.18#runtime\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eSlicing de Slices\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003ccode\u003eSlices\u003c/code\u003e fornecem a capacidade de evitar cópias extras e alocações de \u003ccode\u003eheap\u003c/code\u003e do \u003ccode\u003earray\u003c/code\u003e subjacente\n\n\n quando é necessário isolar certos elementos do \u003ccode\u003earray\u003c/code\u003e subjacente para diferentes operações.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A sintaxe de slicing` é representada pela notação de lista [a:b), o que significa incluir\n\n\n elementos do índice a até b, mas não incluindo b.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice1 := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\nslice2 := slice1[2:4]\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A variável slice2 é um novo valor de \u003ccode\u003eslice\u003c/code\u003e que está compartilhando o mesmo \u003ccode\u003earray\u003c/code\u003e subjacente que a\n\n\n slice1 está usando. No entanto, slice2 só permite acessar os elementos nos índices 2 e 3 (C e D) do\n\n\n array subjacente original do \u003ccode\u003eslice\u003c/code\u003e. O comprimento de slice2 é 2, não 5 como em slice1, e a capacidade é 3,\n\n\n pois agora existem 3 elementos a partir dessa posição de ponteiro.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl4.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl4.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Uma forma melhor de pensar sobre \u003ccode\u003eslicing\u003c/code\u003e é focar no comprimento usando esta notação [a:a+len],\n\n\n onde a representa o índice a até a mais o comprimento. Isso ajudará a reduzir erros ao calcular novos \u003ccode\u003eslices\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Isso pode ser feito usando a função \u003ccode\u003einspect\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc inspectSlice(slice []string) {\n fmt.Printf(\u0026#34;Length[%d] Capacity[%d]\\n\u0026#34;, len(slice), cap(slice))\n for i, s := range slice {\n fmt.Printf(\u0026#34;[%d] %p %s\\n\u0026#34;,\n i,\n \u0026amp;slice[i],\n s)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver isso em ação.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice1 := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\nslice2 := slice1[2:4]\ninspectSlice(slice1)\ninspectSlice(slice2)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eLength[5] Capacity[5]\n[0] 0xc00007e000 A\n[1] 0xc00007e010 B\n[2] 0xc00007e020 C\n[3] 0xc00007e030 D\n[4] 0xc00007e040 E\nLength[2] Capacity[3]\n[0] 0xc00007e020 C \u0026lt;-- SAME AS INDEX 2 IN SLICE 1\n[1] 0xc00007e030 D \u0026lt;-- SAME AS INDEX 3 IN SLICE 1\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Observe como os dois \u003ccode\u003eslices\u003c/code\u003e diferentes estão compartilhando o mesmo \u003ccode\u003earray\u003c/code\u003e subjacente.\n\n\n Isso pode ser visto comparando os endereços de memória.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A vantagem aqui é que não há alocações. O compilador conhece o tamanho do \u003ccode\u003earray\u003c/code\u003e subjacente\n\n\n para a slice1 em tempo de compilação. Passar uma cópia do valor do \u003ccode\u003eslice\u003c/code\u003e para a função \u003ccode\u003einspectSlice\u003c/code\u003e\n\n\n mantém tudo na pilha.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eMutação do Array Subjacente\u003c/h2\u003e\n \n \n \u003cp\u003e\n Quando você usa slice2 para alterar o valor da \u003ccode\u003estring\u003c/code\u003e no índice 0, qualquer valor do \u003ccode\u003eslice\u003c/code\u003e\n\n\n que esteja compartilhando o mesmo \u003ccode\u003earray\u003c/code\u003e subjacente (onde o endereço para aquele índice faz\n\n\n parte do comprimento dessa \u003ccode\u003eslice\u003c/code\u003e) verá a alteração.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice1 := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\nslice2 := slice1[2:4]\nslice2[0] = \u0026#34;CHANGED\u0026#34;\ninspectSlice(slice1)\ninspectSlice(slice2)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eLength[5] Capacity[5]\n[0] 0xc00007e000 A\n[1] 0xc00007e010 B\n[2] 0xc00007e020 CHANGED\n[3] 0xc00007e030 D\n[4] 0xc00007e040 E\nLength[2] Capacity[3]\n[0] 0xc00007e020 CHANGED\n[1] 0xc00007e030 D\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você sempre deve estar ciente quando estiver modificando um valor em uma posição de índice\n\n\n se o \u003ccode\u003earray\u003c/code\u003e subjacente está sendo compartilhado com outro \u003ccode\u003eslice\u003c/code\u003e. Isso é importante para garantir\n\n\n que as alterações não afetem inesperadamente outras partes do seu código que dependem do mesmo \u003ccode\u003earray\u003c/code\u003e subjacente.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl5.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl5.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n E se você usar a função built-in \u003ccode\u003eappend\u003c/code\u003e em vez disso?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice1 := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\nslice2 := slice1[2:4]\nslice2 = append(slice2, \u0026#34;CHANGED\u0026#34;)\ninspectSlice(slice1)\ninspectSlice(slice2)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eLength[5] Capacity[5]\n[0] 0xc00007e000 A\n[1] 0xc00007e010 B\n[2] 0xc00007e020 C\n[3] 0xc00007e030 D\n[4] 0xc00007e040 CHANGED\nLength[3] Capacity[3]\n[0] 0xc00007e020 C\n[1] 0xc00007e030 D\n[2] 0xc00007e040 CHANGED\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função \u003ccode\u003eappend\u003c/code\u003e cria o mesmo efeito colateral, entretanto oculto. Neste caso, trazer mais\n\n\n comprimento da capacidade para slice2 fez com que o valor no endereço \u003ccode\u003e0xc00007e040\u003c/code\u003e\n\n\n fosse alterado. Infelizmente, slice1 já tinha esse endereço como parte do seu comprimento.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl6.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl6.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Uma maneira de evitar o efeito colateral é usar um \u003ccode\u003eslice\u003c/code\u003e de três índices ao construir slice2,\n\n\n para que o comprimento e a capacidade sejam iguais a 2.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice1 := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\nslice2 := slice1[2:4:4]\ninspectSlice(slice1)\ninspectSlice(slice2)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eLength[5] Capacity[5]\n[0] 0xc00007e000 A\n[1] 0xc00007e010 B\n[2] 0xc00007e020 C\n[3] 0xc00007e030 D\n[4] 0xc00007e040 E\nLength[2] Capacity[2]\n[0] 0xc00007e020 C\n[1] 0xc00007e030 D\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A sintaxe para um \u003ccode\u003eslice\u003c/code\u003e de três índices é [a:b:c], onde b e c devem ser os mesmos,\n\n\n já que [a-b] define o comprimento e [a-c] define a capacidade. Agora, o comprimento e a\n\n\n capacidade de slice2 são iguais.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora, você pode usar a função embutida append novamente, como antes.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice1 := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\nslice2 := slice1[2:4:4]\nslice2 = append(slice2, \u0026#34;CHANGED\u0026#34;)\ninspectSlice(slice1)\ninspectSlice(slice2)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eLength[5] Capacity[5]\n[0] 0xc00007e000 A\n[1] 0xc00007e010 B\n[2] 0xc00007e020 C\n[3] 0xc00007e030 D\n[4] 0xc00007e040 E\nLength[3] Capacity[4]\n[0] 0xc000016080 C\n[1] 0xc000016090 D\n[2] 0xc0000160a0 CHANGED\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Observe que após a chamada para \u003ccode\u003eappend\u003c/code\u003e, slice2 possui um novo \u003ccode\u003earray\u003c/code\u003e subjacente.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl7.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl7.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Isso pode ser visto ao comparar os endereços de cada \u003ccode\u003eslice\u003c/code\u003e. Neste caso, a mutação\n\n\n em slice2 não causou um efeito colateral em slice1.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eCopiando Slices Manualmente\u003c/h2\u003e\n \n \n \u003cp\u003e\n Existe uma função embutida chamada \u003ccode\u003ecopy\u003c/code\u003e que permite a cópia superficial de \u003ccode\u003eslices\u003c/code\u003e.\n\n\n Como uma \u003ccode\u003estring\u003c/code\u003e possui um \u003ccode\u003earray\u003c/code\u003e subjacente de bytes que são imutáveis, ela pode ser usada\n\n\n como uma origem, mas nunca como um destino.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eslice1 := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;}\nslice3 := make([]string, len(slice1))\ncopy(slice3, slice1)\n\ninspectSlice(slice1)\ninspectSlice(slice3)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eLength[5] Capacity[5]\n[0] 0xc00005c050 A\n[1] 0xc00005c060 B\n[2] 0xc00005c070 C\n[3] 0xc00005c080 D\n[4] 0xc00005c090 E\nLength[5] Capacity[5]\n[0] 0xc00005c0a0 A\n[1] 0xc00005c0b0 B\n[2] 0xc00005c0c0 C\n[3] 0xc00005c0d0 D\n[4] 0xc00005c0e0 E\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Desde que o \u003ccode\u003eslice\u003c/code\u003e de destino tenha o tipo e o comprimento adequados, a função \u003ccode\u003ebuilt-in\u003c/code\u003e \u003ccode\u003ecopy\u003c/code\u003e pode realizar uma cópia rasa.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eSlices Usam a Mutação Semântica de Ponteiro\u003c/h2\u003e\n \n \n \u003cp\u003e\n É importante lembrar que, mesmo ao usar semântica de valor para mover um \u003ccode\u003eslice\u003c/code\u003e ao redor do programa,\n\n\n ao ler e escrever em um \u003ccode\u003eslice\u003c/code\u003e, você está usando semântica de ponteiro. Compartilhar elementos individuais\n\n\n de um \u003ccode\u003eslice\u003c/code\u003e com diferentes partes do seu programa pode causar efeitos colaterais indesejados.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// Construct a slice of 1 user, set a pointer to that user,\n// use the pointer to update likes.\n\nusers := make([]user, 1)\nptrUsr0 := \u0026amp;users[0]\nptrUsr0.likes\u0026#43;\u0026#43;\n\nfor i := range users {\n fmt.Printf(\u0026#34;User: %d Likes: %d\\n\u0026#34;, i, users[i].likes)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eUser: 0 Likes: 1\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Um \u003ccode\u003eslice\u003c/code\u003e é usada para manter uma coleção de usuários. Em seguida, um ponteiro é\n\n\n definido para o primeiro usuário e usado para atualizar os \u0026#34;likes\u0026#34;. A saída mostra\n\n\n que o uso do ponteiro está funcionando.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl8.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl8.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Então, um novo usuário é adicionado à coleção e o ponteiro é usado novamente para adicionar um \u0026#34;like\u0026#34; ao primeiro usuário.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// Append a new user to the collection. Use the pointer again\n// to update likes.\n\nusers = append(users, user{})\nptrUsr0.likes\u0026#43;\u0026#43;\n\nfor i := range users {\n fmt.Printf(\u0026#34;User: %d Likes: %d\\n\u0026#34;, i, users[i].likes)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eUser: 0 Likes: 1\nUser: 1 Likes: 0\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n No entanto, como a função \u003ccode\u003eappend\u003c/code\u003e substituiu o \u003ccode\u003earray\u003c/code\u003e subjacente por um novo, o ponteiro\n\n\n está atualizando o antigo \u003ccode\u003earray\u003c/code\u003e subjacente e os \u0026#34;likes\u0026#34; são perdidos. A saída mostra que\n\n\n os \u0026#34;likes\u0026#34; para o primeiro usuário não aumentaram.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl9.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl9.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n É importante ter cuidado e saber se um \u003ccode\u003eslice\u003c/code\u003e será usado em uma operação de anexação durante\n\n\n a execução de um programa. Você precisa considerar como compartilha o \u003ccode\u003eslice\u003c/code\u003e.\n\n\n Compartilhar índices individuais pode não ser a melhor ideia. Compartilhar o valor inteiro do \u003ccode\u003eslice\u003c/code\u003e\n\n\n também pode não funcionar quando a operação de anexação está em andamento. Provavelmente, usar um \u003ccode\u003eslice\u003c/code\u003e\n\n\n como campo em uma estrutura (struct) e compartilhar o valor da estrutura é uma maneira melhor de abordar esse problema.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eEficiência na Travessia Linear\u003c/h2\u003e\n \n \n \u003cp\u003e\n A beleza de um \u003ccode\u003eslice\u003c/code\u003e está na sua capacidade de permitir a realização de travessias lineares\n\n\n que são mecanicamente simpáticas, enquanto compartilha dados usando semântica de valor para minimizar alocações de \u003ccode\u003eheap\u003c/code\u003e.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ex := []byte{0x0A, 0x15, 0x0e, 0x28, 0x05, 0x96, 0x0b, 0xd0, 0x0}\n\na := x[0]\nb := binary.LittleEndian.Uint16(x[1:3])\nc := binary.LittleEndian.Uint16(x[3:5])\nd := binary.LittleEndian.Uint32(x[5:9])\n\nprintln(a, b, c, d)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O código está realizando uma travessia linear criando valores de \u003ccode\u003eslice\u003c/code\u003e que leem\n\n\n diferentes seções do array de bytes do início ao fim.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/sl10.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/sl10.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Todos os dados neste código permanecem na pilha. Não são feitas cópias extras dos dados dentro do \u003ccode\u003eslice\u003c/code\u003e de \u003ccode\u003ebytes\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eOs \u003ccode\u003eslices\u003c/code\u003e são como \u003ccode\u003earrays\u003c/code\u003e dinâmicos com funcionalidades especiais e \u003ccode\u003ebuilt-in\u003c/code\u003e.\u003c/li\u003e\n \n \u003cli\u003eExiste uma diferença entre o comprimento e a capacidade de um \u003ccode\u003eslice\u003c/code\u003e, e cada um deles serve a um propósito.\u003c/li\u003e\n \n \u003cli\u003eOs \u003ccode\u003eslices\u003c/code\u003e permitem múltiplas \u0026#34;visões\u0026#34; do mesmo \u003ccode\u003earray\u003c/code\u003e subjacente.\u003c/li\u003e\n \n \u003cli\u003eOs \u003ccode\u003eslices\u003c/code\u003e podem crescer através do uso da função \u003ccode\u003ebulit-in\u003c/code\u003e append.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/go-slices-usage-and-internals\" target=\"_blank\"\u003eGo Slices: usage and internals\u003c/a\u003e - Andrew Gerrand \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/strings\" target=\"_blank\"\u003eStrings, bytes, runes and characters in Go\u003c/a\u003e - Rob Pike \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/slices\" target=\"_blank\"\u003eArrays, slices (and strings): The mechanics of \u0026#39;append\u0026#39;\u003c/a\u003e - Rob Pike \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/08/understanding-slices-in-go-programming.html\" target=\"_blank\"\u003eUnderstanding Slices in Go Programming\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/08/collections-of-unknown-length-in-go.html\" target=\"_blank\"\u003eCollections Of Unknown Length in Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/09/iterating-over-slices-in-go.html\" target=\"_blank\"\u003eIterating Over Slices In Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/09/slices-of-slices-of-slices-in-go.html\" target=\"_blank\"\u003eSlices of Slices of Slices in Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/12/three-index-slices-in-go-12.html\" target=\"_blank\"\u003eThree-Index Slices in Go 1.2\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://github.com/golang/go/wiki/SliceTricks\" target=\"_blank\"\u003eSliceTricks\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://go-review.googlesource.com/c/go/+/347917\" target=\"_blank\"\u003eruntime: Make slice growth formula a bit smoother\u003c/a\u003e - Go Team \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how the capacity of the slice\n// is not available for use.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Create a slice with a length of 5 elements.\n\tfruits := make([]string, 5)\n\tfruits[0] = \"Apple\"\n\tfruits[1] = \"Orange\"\n\tfruits[2] = \"Banana\"\n\tfruits[3] = \"Grape\"\n\tfruits[4] = \"Plum\"\n\n\t// You can't access an index of a slice beyond its length.\n\tfruits[5] = \"Runtime error\"\n\n\t// Error: panic: runtime error: index out of range\n\n\tfmt.Println(fruits)\n}\n","Hash":"8O6F38SjsARSCW3zHXSjYlIXkao="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show the components of a slice. It has a\n// length, capacity and the underlying array.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Create a slice with a length of 5 elements and a capacity of 8.\n\tfruits := make([]string, 5, 8)\n\tfruits[0] = \"Apple\"\n\tfruits[1] = \"Orange\"\n\tfruits[2] = \"Banana\"\n\tfruits[3] = \"Grape\"\n\tfruits[4] = \"Plum\"\n\n\tinspectSlice(fruits)\n}\n\n// inspectSlice exposes the slice header for review.\nfunc inspectSlice(slice []string) {\n\tfmt.Printf(\"Length[%d] Capacity[%d]\\n\", len(slice), cap(slice))\n\tfor i, s := range slice {\n\t\tfmt.Printf(\"[%d] %p %s\\n\",\n\t\t\ti,\n\t\t\t\u0026slice[i],\n\t\t\ts)\n\t}\n}\n","Hash":"eAszlSS0R6s0znZizSjOrsiweK8="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to grow a slice using the built-in function append\n// and how append grows the capacity of the underlying array.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare a nil slice of strings.\n\tvar data []string\n\n\t// Capture the capacity of the slice.\n\tlastCap := cap(data)\n\n\t// Append ~100k strings to the slice.\n\tfor record := 1; record \u003c= 1e5; record++ {\n\n\t\t// Use the built-in function append to add to the slice.\n\t\tvalue := fmt.Sprintf(\"Rec: %d\", record)\n\t\tdata = append(data, value)\n\n\t\t// When the capacity of the slice changes, display the changes.\n\t\tif lastCap != cap(data) {\n\n\t\t\t// Calculate the percent of change.\n\t\t\tcapChg := float64(cap(data)-lastCap) / float64(lastCap) * 100\n\n\t\t\t// Save the new values for capacity.\n\t\t\tlastCap = cap(data)\n\n\t\t\t// Display the results.\n\t\t\tfmt.Printf(\"Addr[%p]\\tIndex[%d]\\t\\tCap[%d - %2.f%%]\\n\",\n\t\t\t\t\u0026data[0],\n\t\t\t\trecord,\n\t\t\t\tcap(data),\n\t\t\t\tcapChg)\n\t\t}\n\t}\n}\n","Hash":"R/zOT8bYNKAxAbOXaJGBJQml+8s="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to takes slices of slices to create different\n// views of and make changes to the underlying array.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Create a slice with a length of 5 elements and a capacity of 8.\n\tslice1 := make([]string, 5, 8)\n\tslice1[0] = \"Apple\"\n\tslice1[1] = \"Orange\"\n\tslice1[2] = \"Banana\"\n\tslice1[3] = \"Grape\"\n\tslice1[4] = \"Plum\"\n\n\tinspectSlice(slice1)\n\n\t// Take a slice of slice1. We want just indexes 2 and 3.\n\t// Parameters are [starting_index : (starting_index + length)]\n\tslice2 := slice1[2:4]\n\tinspectSlice(slice2)\n\n\tfmt.Println(\"*************************\")\n\n\t// Change the value of the index 0 of slice2.\n\tslice2[0] = \"CHANGED\"\n\n\t// Display the change across all existing slices.\n\tinspectSlice(slice1)\n\tinspectSlice(slice2)\n\n\tfmt.Println(\"*************************\")\n\n\t// Make a new slice big enough to hold elements of slice 1 and copy the\n\t// values over using the builtin copy function.\n\tslice3 := make([]string, len(slice1))\n\tcopy(slice3, slice1)\n\tinspectSlice(slice3)\n}\n\n// inspectSlice exposes the slice header for review.\nfunc inspectSlice(slice []string) {\n\tfmt.Printf(\"Length[%d] Capacity[%d]\\n\", len(slice), cap(slice))\n\tfor i, s := range slice {\n\t\tfmt.Printf(\"[%d] %p %s\\n\",\n\t\t\ti,\n\t\t\t\u0026slice[i],\n\t\t\ts)\n\t}\n}\n","Hash":"qRJS5C/sdtXi4CJRhjgNb44TzPo="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how one needs to be careful when appending\n// to a slice when you have a reference to an element.\npackage main\n\nimport \"fmt\"\n\ntype user struct {\n\tlikes int\n}\n\nfunc main() {\n\n\t// Declare a slice of 3 users.\n\tusers := make([]user, 3)\n\n\t// Share the user at index 1.\n\tshareUser := \u0026users[1]\n\n\t// Add a like for the user that was shared.\n\tshareUser.likes++\n\n\t// Display the number of likes for all users.\n\tfor i := range users {\n\t\tfmt.Printf(\"User: %d Likes: %d\\n\", i, users[i].likes)\n\t}\n\n\t// Add a new user.\n\tusers = append(users, user{})\n\n\t// Add another like for the user that was shared.\n\tshareUser.likes++\n\n\t// Display the number of likes for all users.\n\tfmt.Println(\"*************************\")\n\tfor i := range users {\n\t\tfmt.Printf(\"User: %d Likes: %d\\n\", i, users[i].likes)\n\t}\n\n\t// Notice the last like has not been recorded.\n}\n","Hash":"C2T1QkpUC3BwZ/w7ApxFSL+xRuw="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n/*\n\thttps://blog.golang.org/strings\n\n\tGo source code is always UTF-8.\n\tA string holds arbitrary bytes.\n\tA string literal, absent byte-level escapes, always holds valid UTF-8 sequences.\n\tThose sequences represent Unicode code points, called runes.\n\tNo guarantee is made in Go that characters in strings are normalized.\n\n\t----------------------------------------------------------------------------\n\n\tMultiple runes can represent different characters:\n\n\tThe lower case grave-accented letter à is a character, and it's also a code\n\tpoint (U+00E0), but it has other representations.\n\n\tWe can use the \"combining\" grave accent code point, U+0300, and attach it to\n\tthe lower case letter a, U+0061, to create the same character à.\n\n\tIn general, a character may be represented by a number of different sequences\n\tof code points (runes), and therefore different sequences of UTF-8 bytes.\n*/\n\n// Sample program to show how strings have a UTF-8 encoded byte array.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"unicode/utf8\"\n)\n\nfunc main() {\n\n\t// Declare a string with both chinese and english characters.\n\ts := \"世界 means world\"\n\n\t// UTFMax is 4 -- up to 4 bytes per encoded rune.\n\tvar buf [utf8.UTFMax]byte\n\n\t// Iterate over the string.\n\tfor i, r := range s {\n\n\t\t// Capture the number of bytes for this rune.\n\t\trl := utf8.RuneLen(r)\n\n\t\t// Calculate the slice offset for the bytes associated\n\t\t// with this rune.\n\t\tsi := i + rl\n\n\t\t// Copy of rune from the string to our buffer.\n\t\tcopy(buf[:], s[i:si])\n\n\t\t// Display the details.\n\t\tfmt.Printf(\"%2d: %q; codepoint: %#6x; encoded bytes: %#v\\n\", i, r, r, buf[:rl])\n\t}\n}\n","Hash":"RVs2+eAKQpRnyeDxYYxyiqA1gQ4="},{"Name":"example7.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare and use variadic functions.\npackage main\n\nimport \"fmt\"\n\n// user is a struct type that declares user information.\ntype user struct {\n\tid int\n\tname string\n}\n\nfunc main() {\n\n\t// Declare and initialize a value of type user.\n\tu1 := user{\n\t\tid: 1432,\n\t\tname: \"Betty\",\n\t}\n\n\t// Declare and initialize a value of type user.\n\tu2 := user{\n\t\tid: 4367,\n\t\tname: \"Janet\",\n\t}\n\n\t// Display both user values.\n\tdisplay(u1, u2)\n\n\t// Create a slice of user values.\n\tu3 := []user{\n\t\t{24, \"Bill\"},\n\t\t{32, \"Joan\"},\n\t}\n\n\t// Display all the user values from the slice.\n\tdisplay(u3...)\n\n\tchange(u3...)\n\tfmt.Println(\"**************************\")\n\tfor _, u := range u3 {\n\t\tfmt.Printf(\"%+v\\n\", u)\n\t}\n}\n\n// display can accept and display multiple values of user types.\nfunc display(users ...user) {\n\tfmt.Println(\"**************************\")\n\tfor _, u := range users {\n\t\tfmt.Printf(\"%+v\\n\", u)\n\t}\n}\n\n// change shows how the backing array is shared.\nfunc change(users ...user) {\n\tusers[1] = user{99, \"Same Backing Array\"}\n}\n","Hash":"4qs5nJ/l6k9vfJeKZan/elsz76M="},{"Name":"example8.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how the for range has both value and pointer semantics.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Using the value semantic form of the for range.\n\tfriends := []string{\"Annie\", \"Betty\", \"Charley\", \"Doug\", \"Edward\"}\n\tfor _, v := range friends {\n\t\tfriends = friends[:2]\n\t\tfmt.Printf(\"v[%s]\\n\", v)\n\t}\n\n\t// Using the pointer semantic form of the for range.\n\tfriends = []string{\"Annie\", \"Betty\", \"Charley\", \"Doug\", \"Edward\"}\n\tfor i := range friends {\n\t\tfriends = friends[:2]\n\t\tfmt.Printf(\"v[%s]\\n\", friends[i])\n\t}\n}\n","Hash":"1pl/XfLmE6pGQXWeS87PVSNplOY="},{"Name":"example9.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how slices allow for efficient linear traversals.\npackage main\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n)\n\nfunc main() {\n\n\t// Given a stream of bytes to be processed.\n\tx := []byte{0x0A, 0x15, 0x0e, 0x28, 0x05, 0x96, 0x0b, 0xd0, 0x0}\n\n\t// Perform a linear traversal across the bytes, never making\n\t// copies of the actual data but still passing those bytes\n\t// to the binary function for processing.\n\n\ta := x[0]\n\tb := binary.LittleEndian.Uint16(x[1:3])\n\tc := binary.LittleEndian.Uint16(x[3:5])\n\td := binary.LittleEndian.Uint32(x[5:9])\n\n\t// The result is zero allocation data access that is mechanically\n\t// sympathetic with the hardware.\n\n\tfmt.Println(a, b, c, d)\n}\n","Hash":"hL9bNxb/iuKyYLUhyeU2ZLUan5M="},{"Name":"example10.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use a third index slice.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Create a slice of strings with different types of fruit.\n\tslice := []string{\"Apple\", \"Orange\", \"Banana\", \"Grape\", \"Plum\"}\n\tinspectSlice(slice)\n\n\t// Take a slice of slice. We want just index 2\n\ttakeOne := slice[2:3]\n\tinspectSlice(takeOne)\n\n\t// Take a slice of just index 2 with a length and capacity of 1\n\ttakeOneCapOne := slice[2:3:3] // Use the third index position to\n\tinspectSlice(takeOneCapOne) // set the capacity to 1.\n\n\t// Append a new element which will create a new\n\t// underlying array to increase capacity.\n\ttakeOneCapOne = append(takeOneCapOne, \"Kiwi\")\n\tinspectSlice(takeOneCapOne)\n}\n\n// inspectSlice exposes the slice header for review.\nfunc inspectSlice(slice []string) {\n\tfmt.Printf(\"Length[%d] Capacity[%d]\\n\", len(slice), cap(slice))\n\tfor i, s := range slice {\n\t\tfmt.Printf(\"[%d] %p %s\\n\",\n\t\t\ti,\n\t\t\t\u0026slice[i],\n\t\t\ts)\n\t}\n}\n","Hash":"fTjke16efysnLDguHQAMt5ALCmE="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Declare um \u003ccode\u003eslice\u003c/code\u003e vazio de inteiros. Crie um \u003ccode\u003eloop\u003c/code\u003e que adiciona 10 valores ao \u003ccode\u003eslice\u003c/code\u003e.\n\n\n Itere sobre o \u003ccode\u003eslice\u003c/code\u003e e exiba cada valor.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Declare um \u003ccode\u003eslice\u003c/code\u003e de cinco \u003ccode\u003estrings\u003c/code\u003e e inicialize o \u003ccode\u003eslice\u003c/code\u003e com valores literais de \u003ccode\u003estring\u003c/code\u003e.\n\n\n Exiba todos os elementos. Pegue um \u003ccode\u003eslice\u003c/code\u003e dos índices um e dois e exiba a posição do índice e o\n\n\n valor de cada elemento no novo \u003ccode\u003eslice\u003c/code\u003e.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a nil slice of integers. Create a loop that appends 10 values to the\n// slice. Iterate over the slice and display each value.\n//\n// Declare a slice of five strings and initialize the slice with string literal\n// values. Display all the elements. Take a slice of index one and two\n// and display the index position and value of each element in the new slice.\npackage main\n\n// Add imports.\n\nfunc main() {\n\n\t// Declare a nil slice of integers.\n\n\t// Append numbers to the slice.\n\n\t// Display each value in the slice.\n\n\t// Declare a slice of strings and populate the slice with names.\n\n\t// Display each index position and slice value.\n\n\t// Take a slice of index 1 and 2 of the slice of strings.\n\n\t// Display each index position and slice values for the new slice.\n}\n","Hash":"EUH8tWtJoMtTaDYQj8TsjP6bfbs="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a nil slice of integers. Create a loop that appends 10 values to the\n// slice. Iterate over the slice and display each value.\n//\n// Declare a slice of five strings and initialize the slice with string literal\n// values. Display all the elements. Take a slice of index one and two\n// and display the index position and value of each element in the new slice.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare a nil slice of integers.\n\tvar numbers []int\n\n\t// Append numbers to the slice.\n\tfor i := 0; i \u003c 10; i++ {\n\t\tnumbers = append(numbers, i*10)\n\t}\n\n\t// Display each value.\n\tfor _, number := range numbers {\n\t\tfmt.Println(number)\n\t}\n\n\t// Declare a slice of strings.\n\tnames := []string{\"Bill\", \"Joan\", \"Jim\", \"Cathy\", \"Beth\"}\n\n\t// Display each index position and name.\n\tfor i, name := range names {\n\t\tfmt.Printf(\"Index: %d Name: %s\\n\", i, name)\n\t}\n\n\t// Take a slice of index 1 and 2.\n\tslice := names[1:3]\n\n\t// Display the value of the new slice.\n\tfor i, name := range slice {\n\t\tfmt.Printf(\"Index: %d Name: %s\\n\", i, name)\n\t}\n}\n","Hash":"QH1TKKOx3v9d7V8gMrU1qBNm4GE="}]}]} ,"composition-grouping":{"Title":"Agrupamento com Tipos","Description":"É importante lembrar que em Go os conceitos de subtipagem ou subclasse realmente não existem e esses padrões de design devem ser evitados.","Pages":[{"Title":"Agrupamento com Tipos","Content":"\n \u003ch2\u003eAgrupamento com Tipos\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n É importante lembrar que em Go os conceitos de subtipagem ou subclasse realmente não existem e esses padrões de design devem ser evitados.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Agrupamento por Estado\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Agrupamento por Comportamento\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eAgrupando Diferentes Tipos de Dados\u003c/h2\u003e\n \n \n \u003cp\u003e\n É importante lembrar que em Go os conceitos de subtipagem ou subclasse realmente não existem e esses padrões de design devem ser evitados.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O código seguinte é um anti-padrão que você não deve seguir nem implementar.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Animal struct {\n Name string\n IsMammal bool\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O tipo Animal é declarado como um tipo base que tenta definir dados que são comuns a todos os animais. Você também tenta fornecer algum comportamento comum a um animal.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (a *Animal) Speak() {\n fmt.Println(\u0026#34;UGH!\u0026#34;,\n \u0026#34;My name is\u0026#34;, a.Name, \u0026#34;, it is\u0026#34;, a.IsMammal, \u0026#34;I am a mammal\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A maioria dos animais tem a capacidade de se comunicar de alguma forma. No entanto, tentar aplicar esse comportamento comum a apenas um animal não faz sentido. Neste ponto, você não tem ideia de que som esse animal faz, então você escreve \u0026#34;UGH\u0026#34;.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Dog struct {\n Animal\n PackFactor int\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Agora os problemas reais começam. Estou tentando usar a incorporação (embedding) para fazer com que um Cachorro seja tudo o que um Animal é e mais. À primeira vista, isso parecerá funcionar, mas haverá problemas. Dito isso, um Cachorro tem uma maneira específica de se comunicar.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (d *Dog) Speak() {\n fmt.Println(\u0026#34;Woof!\u0026#34;,\n \u0026#34;My name is\u0026#34;, d.Name,\n \u0026#34;, it is\u0026#34;, d.IsMammal,\n \u0026#34;I am a mammal with a pack factor of\u0026#34;, d.PackFactor)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Na implementação do método \u003ccode\u003eSpeak\u003c/code\u003e, você pode substituir \u0026#34;UGH\u0026#34; por \u0026#34;Woof\u0026#34;. Isso é específico para como um cachorro se comunica.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Cat struct {\n Animal\n ClimbFactor int\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Se você vai ter um Cachorro que representa um Animal, então você também precisa ter um Gato. Usando a incorporação (embedding), um Gato é tudo o que um Animal é e mais.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (c *Cat) Speak() {\n fmt.Println(\u0026#34;Meow!\u0026#34;,\n \u0026#34;My name is\u0026#34;, c.Name,\n \u0026#34;, it is\u0026#34;, c.IsMammal,\n \u0026#34;I am a mammal with a climb factor of\u0026#34;, c.ClimbFactor)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Na implementação do método \u003ccode\u003eSpeak\u003c/code\u003e, você pode substituir \u0026#34;UGH\u0026#34; por \u0026#34;Meow\u0026#34;. Isso é específico para como um gato se comunica.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Tudo parece estar bem, e parece que a incorporação (embedding) está fornecendo a mesma funcionalidade que a herança em outras linguagens. Então, você tenta agrupar cães e gatos pelo fato de terem um DNA comum de serem animais.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eanimals := []Animal{\n Dog{\n Animal: Animal{\n Name: \u0026#34;Fido\u0026#34;,\n IsMammal: true,\n },\n PackFactor: 5,\n },\n\n Cat{\n Animal: Animal{\n Name: \u0026#34;Milo\u0026#34;,\n IsMammal: true,\n },\n ClimbFactor: 4,\n },\n}\n\nfor _, animal := range animals {\n animal.Speak()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando você tenta fazer isso, o compilador reclama que um Cachorro e um Gato não são um Animal, e isso é verdade. A incorporação (embedding) não é a mesma coisa que a herança, e este é o padrão do qual preciso me afastar. Um Cachorro é um Cachorro, um Gato é um Gato e um Animal é um Animal. Não posso passar Cachorros e Gatos como se fossem Animais, porque não são.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esse tipo de mecanismo também não é muito flexível. Requer configuração por parte do desenvolvedor, e a menos que você tenha acesso ao código, não pode fazer alterações de configuração ao longo do tempo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se esta não é a forma de construir uma coleção de Cachorros e Gatos, como podemos fazer isso em Go? Não se trata de agrupar por DNA comum, trata-se de agrupar por comportamento comum. O comportamento é a chave.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Speaker interface {\n Speak()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Se você usar uma interface, poderá definir o conjunto comum de métodos comportamentais que deseja agrupar diferentes tipos de dados.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003espeakers := []Speaker{\n \u0026amp;Dog{\n Animal: Animal{\n Name: \u0026#34;Fido\u0026#34;,\n IsMammal: true,\n },\n PackFactor: 5,\n },\n \u0026amp;Cat{\n Animal: Animal{\n Name: \u0026#34;Milo\u0026#34;,\n IsMammal: true,\n },\n ClimbFactor: 4,\n },\n}\n\nfor _, speaker := range speakers {\n speaker.Speak()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n No novo código, agora você pode agrupar Cachorros e Gatos com base no conjunto comum de comportamentos, que é o fato de que Cachorros e Gatos podem se comunicar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Na verdade, o tipo Animal é realmente uma poluição de tipos, porque declarar um tipo apenas para compartilhar um conjunto de estados comuns é um indício de código ruim e deve ser evitado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Dog struct {\n Name string\n IsMammal bool\n PackFactor int\n}\n\ntype Cat struct {\n Name string\n IsMammal bool\n ClimbFactor int\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste caso específico, você preferiria ver o tipo Animal removido e os campos copiados e colados nos tipos Dog e Cat. Mais tarde, você terá notas sobre padrões melhores que eliminam esses cenários de acontecerem.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Aqui estão os problemas de código do código original:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eO tipo Animal fornece uma camada de abstração de estado reutilizável.\u003c/li\u003e\n \n \u003cli\u003eO programa nunca precisa criar ou usar exclusivamente um valor do tipo Animal.\u003c/li\u003e\n \n \u003cli\u003eA implementação do método Speak para o tipo Animal é generalizada.\u003c/li\u003e\n \n \u003cli\u003eO método Speak para o tipo Animal nunca será chamado.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Diretrizes para declarar tipos:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eDeclare tipos que representem algo novo ou único.\u003c/li\u003e\n \n \u003cli\u003eNão crie aliases (apelidos) apenas para melhorar a legibilidade.\u003c/li\u003e\n \n \u003cli\u003eValide se um valor de qualquer tipo é criado ou usado por si só.\u003c/li\u003e\n \n \u003cli\u003eIncorpore (embed) tipos não porque você precisa do estado, mas porque você precisa do comportamento.\u003c/li\u003e\n \n \u003cli\u003eSe você não está pensando em comportamento, está se limitando ao design que não pode ser expandido no futuro sem mudanças em cascata no código.\u003c/li\u003e\n \n \u003cli\u003eQuestione tipos que são aliases ou abstrações para um tipo existente.\u003c/li\u003e\n \n \u003cli\u003eQuestione tipos cujo único propósito é compartilhar um conjunto comum de estados.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eNão Projete com Interfaces\u003c/h2\u003e\n \n \n \u003cp\u003e\n Infelizmente, muitos desenvolvedores tentam resolver problemas de forma abstrata desde o início. Eles se concentram imediatamente em interfaces, o que leva à poluição de interfaces. Como desenvolvedor, você opera em um de dois modos: programador e depois engenheiro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando você está programando, está focado em fazer um trecho de código funcionar. Tentando resolver o problema e derrubar barreiras. Provar que suas ideias iniciais funcionam. Isso é tudo o que importa nesse momento. Essa programação deve ser feita de forma concreta e nunca estará pronta para produção.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Uma vez que você tenha um protótipo de código que resolve o problema, você precisa mudar para o modo de engenharia. É necessário se concentrar em como escrever o código em um nível micro para semântica de dados e legibilidade, e também em um nível macro para modelos mentais e manutenibilidade. Além disso, é necessário focar em erros e estados de falha.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esse trabalho é feito em um ciclo de refatoração. Refatoração para legibilidade, eficiência, abstração e testabilidade. A abstração é apenas uma das várias refatorações que precisam ser realizadas. Isso funciona melhor quando você começa com um trecho de código concreto e, em seguida, DESCOBRE as interfaces necessárias. Não aplique abstrações a menos que sejam absolutamente necessárias.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Cada problema que você resolve com código é um problema de dados que requer que você escreva transformações de dados. Se você não entende os dados, você não entende o problema. Se você não entende o problema, não pode escrever nenhum código. Começar com uma solução concreta baseada em estruturas de dados concretas é crucial. Como disse Rob Pike:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Os dados dominam. Se você escolheu as estruturas de dados certas e organizou as coisas bem, os algoritmos quase sempre serão autoevidentes.\u0026#34; - Rob Pike\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando a abstração é necessária? Quando você identifica um ponto no código em que os dados podem mudar e deseja minimizar os efeitos cascata que resultariam disso. Você pode usar a abstração para tornar o código testável, mas deve tentar evitá-la, se possível. As melhores funções testáveis são aquelas que recebem dados brutos e retornam dados brutos. Não deve importar de onde os dados vêm ou para onde vão.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n No final, comece com uma solução concreta para cada problema, mesmo que a maior parte seja apenas programação. Em seguida, descubra as interfaces que são absolutamente necessárias para o código hoje.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Não projete com interfaces, descubra-as.\u0026#34; - Rob Pike\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This is an example of using type hierarchies with a OOP pattern.\n// This is not something we want to do in Go. Go does not have the\n// concept of sub-typing. All types are their own and the concepts of\n// base and derived types do not exist in Go. This pattern does not\n// provide a good design principle in a Go program.\npackage main\n\nimport \"fmt\"\n\n// Animal contains all the base fields for animals.\ntype Animal struct {\n\tName string\n\tIsMammal bool\n}\n\n// Speak provides generic behavior for all animals and\n// how they speak.\nfunc (a *Animal) Speak() {\n\tfmt.Printf(\n\t\t\"UGH! My name is %s, it is %t I am a mammal\\n\",\n\t\ta.Name,\n\t\ta.IsMammal,\n\t)\n}\n\n// Dog contains everything an Animal is but specific\n// attributes that only a Dog has.\ntype Dog struct {\n\tAnimal\n\tPackFactor int\n}\n\n// Speak knows how to speak like a dog.\nfunc (d *Dog) Speak() {\n\tfmt.Printf(\n\t\t\"Woof! My name is %s, it is %t I am a mammal with a pack factor of %d.\\n\",\n\t\td.Name,\n\t\td.IsMammal,\n\t\td.PackFactor,\n\t)\n}\n\n// Cat contains everything an Animal is but specific\n// attributes that only a Cat has.\ntype Cat struct {\n\tAnimal\n\tClimbFactor int\n}\n\n// Speak knows how to speak like a cat.\nfunc (c *Cat) Speak() {\n\tfmt.Printf(\n\t\t\"Meow! My name is %s, it is %t I am a mammal with a climb factor of %d.\\n\",\n\t\tc.Name,\n\t\tc.IsMammal,\n\t\tc.ClimbFactor,\n\t)\n}\n\nfunc main() {\n\n\t// Create a list of Animals that know how to speak.\n\tanimals := []Animal{\n\n\t\t// Create a Dog by initializing its Animal parts\n\t\t// and then its specific Dog attributes.\n\t\tDog{\n\t\t\tAnimal: Animal{\n\t\t\t\tName: \"Fido\",\n\t\t\t\tIsMammal: true,\n\t\t\t},\n\t\t\tPackFactor: 5,\n\t\t},\n\n\t\t// Create a Cat by initializing its Animal parts\n\t\t// and then its specific Cat attributes.\n\t\tCat{\n\t\t\tAnimal: Animal{\n\t\t\t\tName: \"Milo\",\n\t\t\t\tIsMammal: true,\n\t\t\t},\n\t\t\tClimbFactor: 4,\n\t\t},\n\t}\n\n\t// Have the Animals speak.\n\tfor _, animal := range animals {\n\t\tanimal.Speak()\n\t}\n}\n","Hash":"gbo5/wkQcJsDQQKbqYjpvkFTzCo="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This is an example of using composition and interfaces. This is\n// something we want to do in Go. We will group common types by\n// their behavior and not by their state. This pattern does\n// provide a good design principle in a Go program.\npackage main\n\nimport \"fmt\"\n\n// Speaker provide a common behavior for all concrete types\n// to follow if they want to be a part of this group. This\n// is a contract for these concrete types to follow.\ntype Speaker interface {\n\tSpeak()\n}\n\n// Dog contains everything a Dog needs.\ntype Dog struct {\n\tName string\n\tIsMammal bool\n\tPackFactor int\n}\n\n// Speak knows how to speak like a dog.\n// This makes a Dog now part of a group of concrete\n// types that know how to speak.\nfunc (d *Dog) Speak() {\n\tfmt.Printf(\n\t\t\"Woof! My name is %s, it is %t I am a mammal with a pack factor of %d.\\n\",\n\t\td.Name,\n\t\td.IsMammal,\n\t\td.PackFactor,\n\t)\n}\n\n// Cat contains everything a Cat needs.\ntype Cat struct {\n\tName string\n\tIsMammal bool\n\tClimbFactor int\n}\n\n// Speak knows how to speak like a cat.\n// This makes a Cat now part of a group of concrete\n// types that know how to speak.\nfunc (c *Cat) Speak() {\n\tfmt.Printf(\n\t\t\"Meow! My name is %s, it is %t I am a mammal with a climb factor of %d.\\n\",\n\t\tc.Name,\n\t\tc.IsMammal,\n\t\tc.ClimbFactor,\n\t)\n}\n\nfunc main() {\n\n\t// Create a list of Animals that know how to speak.\n\tspeakers := []Speaker{\n\n\t\t// Create a Dog by initializing its Animal parts\n\t\t// and then its specific Dog attributes.\n\t\t\u0026Dog{\n\t\t\tName: \"Fido\",\n\t\t\tIsMammal: true,\n\t\t\tPackFactor: 5,\n\t\t},\n\n\t\t// Create a Cat by initializing its Animal parts\n\t\t// and then its specific Cat attributes.\n\t\t\u0026Cat{\n\t\t\tName: \"Milo\",\n\t\t\tIsMammal: true,\n\t\t\tClimbFactor: 4,\n\t\t},\n\t}\n\n\t// Have the Animals speak.\n\tfor _, spkr := range speakers {\n\t\tspkr.Speak()\n\t}\n}\n","Hash":"8SagnKvE4NUre5wWlrTg+UO9vlM="}]}]} ,"composition-pollution":{"Title":"Poluição de Interface","Description":"A poluição de interfaces ocorre pelo fato de as pessoas estarem projetando software com interfaces em vez de descobri-las.","Pages":[{"Title":"Poluição de Interface","Content":"\n \u003ch2\u003ePoluição de Interface\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n A poluição de interfaces ocorre pelo fato de as pessoas estarem projetando software com interfaces em vez de descobri-las.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExample\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Crie Poluição de Interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExample\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Remova Poluição de Interface\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003ePoluição de Interface\u003c/h2\u003e\n \n \n \u003cp\u003e\n A poluição de interfaces ocorre porque as pessoas estão projetando software com interfaces \n\n\n em vez de descobri-las. Você deve primeiro projetar uma solução concreta para o problema. \n\n\n Em seguida, você pode descobrir onde o programa precisa ser polimórfico, se for o caso.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Aqui estão algumas coisas que ouvi de outros desenvolvedores.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Estou usando interfaces porque precisamos usar interfaces\u0026#34;.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Não. Não é necessário usar interfaces. Usamos interfaces quando é prático e razoável fazê-lo. \n\n\n Há um custo no uso de interfaces: um nível de indireção e alocação quando armazenamos valores \n\n\n concretos dentro delas. A menos que o custo da alocação compense o que estou ganhando com o \n\n\n desacoplamento, você não deveria estar usando interfaces.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Eu preciso ser capaz de testar meu código, então preciso usar interfaces\u0026#34;.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Não. Você deve projetar minha API para o usuário em primeiro lugar, não para meus testes. \n\n\n Se a API não for testável, você deve questionar se ela é utilizável. Existem diferentes \n\n\n camadas de APIs também. As APIs de nível mais baixo, não exportadas, podem e devem se \n\n\n concentrar na testabilidade. As APIs de nível mais alto, exportadas, precisam se concentrar \n\n\n na usabilidade.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Funções que aceitam dados brutos como entrada e retornam dados brutos como saída são as mais \n\n\n testáveis. Separe a transformação de dados de onde os dados vêm e para onde eles estão indo. \n\n\n Isso é um exercício de refatoração que você precisa realizar durante o ciclo de codificação \n\n\n de engenharia.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Abaixo, há um exemplo que cria poluição de interfaces ao usar uma interface de maneira inadequada \n\n\n quando ela não é necessária.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Server interface {\n Start() error\n Stop() error\n Wait() error\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A interface Server define um contrato para servidores TCP. O problema aqui é \n\n\n que você não precisa de um contrato, você precisa de uma implementação. Haverá \n\n\n apenas uma implementação, especialmente porque você é quem está implementando. \n\n\n Você não precisa que outra pessoa o faça por você.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Além disso, esta interface é baseada em um substantivo e não em um verbo. Tipos \n\n\n concretos são substantivos, pois representam o problema concreto. Interfaces \n\n\n descrevem o comportamento e Server não é um comportamento.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Aqui estão algumas maneiras de identificar a poluição de interfaces:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eUm pacote declara uma interface que corresponde a toda a API de seu próprio tipo concreto.\u003c/li\u003e\n \n \u003cli\u003eAs interfaces são exportadas, mas os tipos concretos que implementam a interface não são exportados.\u003c/li\u003e\n \n \u003cli\u003eA função de fábrica para o tipo concreto retorna o valor da interface com o valor do tipo concreto não exportado dentro.\u003c/li\u003e\n \n \u003cli\u003eA interface pode ser removida e nada muda para o usuário da API.\u003c/li\u003e\n \n \u003cli\u003eA interface não está desacoplando a API de possíveis alterações.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Diretrizes em relação à poluição de interfaces:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Use uma interface:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eQuando os usuários da API precisam fornecer um detalhe de implementação.\u003c/li\u003e\n \n \u003cli\u003eQuando as APIs têm múltiplas implementações que precisam ser mantidas.\u003c/li\u003e\n \n \u003cli\u003eQuando partes das APIs que podem mudar foram identificadas e exigem desacoplamento.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Questione uma interface:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eQuando seu único propósito é escrever APIs testáveis (escreva APIs utilizáveis primeiro).\u003c/li\u003e\n \n \u003cli\u003eQuando ela não está fornecendo suporte para que a API se desacople de possíveis alterações.\u003c/li\u003e\n \n \u003cli\u003eQuando não está claro como a interface melhora o código.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This is an example that creates interface pollution\n// by improperly using an interface when one is not needed.\npackage main\n\n// Server defines a contract for tcp servers.\ntype Server interface {\n\tStart() error\n\tStop() error\n\tWait() error\n}\n\n// server is our Server implementation.\ntype server struct {\n\thost string\n\n\t// PRETEND THERE ARE MORE FIELDS.\n}\n\n// NewServer returns an interface value of type Server\n// with a server implementation.\nfunc NewServer(host string) Server {\n\n\t// SMELL - Storing an unexported type pointer in the interface.\n\treturn \u0026server{host}\n}\n\n// Start allows the server to begin to accept requests.\nfunc (s *server) Start() error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\n// Stop shuts the server down.\nfunc (s *server) Stop() error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\n// Wait prevents the server from accepting new connections.\nfunc (s *server) Wait() error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\nfunc main() {\n\n\t// Create a new Server.\n\tsrv := NewServer(\"localhost\")\n\n\t// Use the API.\n\tsrv.Start()\n\tsrv.Stop()\n\tsrv.Wait()\n}\n\n// =============================================================================\n\n// NOTES:\n\n// Smells:\n// * The package declares an interface that matches the entire API of its own concrete type.\n// * The interface is exported but the concrete type is unexported.\n// * The factory function returns the interface value with the unexported concrete type value inside.\n// * The interface can be removed and nothing changes for the user of the API.\n// * The interface is not decoupling the API from change.\n","Hash":"Ud2Kl3RAVw0t+77KTkApxAGhY1Q="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This is an example that removes the interface pollution by\n// removing the interface and using the concrete type directly.\npackage main\n\n// Server is our Server implementation.\ntype Server struct {\n\thost string\n\n\t// PRETEND THERE ARE MORE FIELDS.\n}\n\n// NewServer returns an interface value of type Server\n// with a server implementation.\nfunc NewServer(host string) *Server {\n\n\t// SMELL - Storing an unexported type pointer in the interface.\n\treturn \u0026Server{host}\n}\n\n// Start allows the server to begin to accept requests.\nfunc (s *Server) Start() error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\n// Stop shuts the server down.\nfunc (s *Server) Stop() error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\n// Wait prevents the server from accepting new connections.\nfunc (s *Server) Wait() error {\n\n\t// PRETEND THERE IS A SPECIFIC IMPLEMENTATION.\n\treturn nil\n}\n\nfunc main() {\n\n\t// Create a new Server.\n\tsrv := NewServer(\"localhost\")\n\n\t// Use the API.\n\tsrv.Start()\n\tsrv.Stop()\n\tsrv.Wait()\n}\n\n// =============================================================================\n\n// NOTES:\n\n// Here are some guidelines around interface pollution:\n// * Use an interface:\n// * When users of the API need to provide an implementation detail.\n// * When API’s have multiple implementations that need to be maintained.\n// * When parts of the API that can change have been identified and require decoupling.\n// * Question an interface:\n// * When its only purpose is for writing testable API’s (write usable API’s first).\n// * When it’s not providing support for the API to decouple from change.\n// * When it's not clear how the interface makes the code better.\n","Hash":"w2xmDI3uwDuuc6v6n6fFQal1Zuo="}]}]} ,"data_race":{"Title":"Data Race","Description":"Uma Data Race ocorre quando duas ou mais Goroutines tentam acessar a mesma localização de memória ao mesmo tempo,","Pages":[{"Title":"Data Race","Content":"\n \u003ch2\u003eData Race\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Uma Data Race ocorre quando duas ou mais Goroutines tentam acessar a mesma \n\n\n localização de memória ao mesmo tempo, sendo que pelo menos uma Goroutine está \n\n\n realizando uma escrita. Quando isso acontece, é impossível prever o resultado. Esse \n\n\n tipo de erro é difícil de encontrar porque causa problemas que sempre parecem aleatórios.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esses ~8 minutes do Scott Meyers são ótimos para ouvir :\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003ca href=\"https://youtu.be/WDIkqP4JbkE?t=1809\" target=\"_blank\"\u003eCPU Caches and Why You Care 30:09-38:30\u003c/a\u003e\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Data Race\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Incrementos Atômicos\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Mutex\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Mutexes de Leitura/Escrita\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Map Data Race\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e Interface Baseada em Data Race\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExemplo de Data Race\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este é um ótimo exemplo de uma Data Race e de como elas podem \n\n\n ficar ocultas por anos e, eventualmente, aparecer em momentos estranhos \n\n\n e causar corrupção de dados.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar counter int\n\nfunc main() {\n const grs = 2\n\n var wg sync.WaitGroup\n wg.Add(grs)\n\n for g := 0; g \u0026lt; grs; g\u0026#43;\u0026#43; {\n go func() {\n for i := 0; i \u0026lt; 2; i\u0026#43;\u0026#43; {\n value := counter\n value\u0026#43;\u0026#43;\n counter = value\n }\n wg.Done()\n }()\n }\n\n wg.Wait()\n fmt.Println(\u0026#34;Counter:\u0026#34;, counter)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este programa cria duas Goroutines que acessam a mesma variável do tipo integer, \n\n\n incrementando a variável duas vezes. As Goroutines realizam uma operação de leitura, \n\n\n modificação e escrita no estado compartilhado manualmente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar counter int\n\nfunc main() {\n . . .\n\n go func() {\n for i := 0; i \u0026lt; 2; i\u0026#43;\u0026#43; {\n value := counter\n value\u0026#43;\u0026#43;\n counter = value\n }\n wg.Done()\n }()\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver o acesso ao estado compartilhado dentro do loop \u0026#34;for\u0026#34;. Quando você compila \n\n\n e executa este programa, obtém a resposta correta de 4 a cada vez.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e$ ./example1\nFinal Counter: 4\n\n$ ./example1\nFinal Counter: 4\n\n$ ./example1\nFinal Counter: 4\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Como isso funciona?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eG1 Shared State: 0 G2\n----------------------------------------------------------------------------\nRead: 0\nModify: 1\nWrite: 1 Shared State: 1\nContext Switch \n Read: 1\n Modify: 2\n Shared State: 2 Write: 2\n Context Switch \nRead: 2\nModify: 3\nWrite: 3 Shared State: 3\nTerminate\n Read: 3\n Modify: 4\n Shared State: 4 Write: 4\n Terminate\n----------------------------------------------------------------------------\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n As operações de leitura, modificação e escrita estão ocorrendo sem interrupções. \n\n\n Apenas porque estou obtendo a resposta correta não significa que não haja um problema. \n\n\n O que acontece se você adicionar uma declaração de log no meio da operação de leitura, \n\n\n modificação e escrita?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar counter int\n\nfunc main() {\n . . .\n\n go func() {\n for i := 0; i \u0026lt; 2; i\u0026#43;\u0026#43; {\n value := counter\n value\u0026#43;\u0026#43;\n log.Println(\u0026#34;logging\u0026#34;) \u0026lt;-- Add Logging Here\n counter = value\n }\n wg.Done()\n }()\n\n . . .\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Se você executar esse programa, você não obterá mais o mesmo resultado de 4; agora \n\n\n você obterá a resposta de 2.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e$ ./example1\nFinal Counter: 2\n\n$ ./example1\nFinal Counter: 2\n\n$ ./example1\nFinal Counter: 2\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O que está acontecendo? Você está encontrando um bug de Data Race que existia \n\n\n antes, mas não estava ocorrendo. A chamada para o log agora está fazendo com que o \n\n\n scheduler faça uma troca de contexto entre as duas Goroutines em um momento \n\n\n inadequado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eG1 Shared State: 0 G2\n----------------------------------------------------------------------------\nRead: 0\nModify: 1\nContext Switch\n Read: 0\n Modify: 1\n Context Switch \nWrite: 1 Shared State: 1\nRead: 1\nModify: 2\nContext Switch\n Shared State: 1 Write: 1\n Read: 1\n Modify: 2\n Context Switch \nWrite: 2 Shared State: 2\nTerminate\n Shared State: 2 Write: 2\n Terminate\n----------------------------------------------------------------------------\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Após a operação de modificação, ocorre uma troca de contexto. As três operações não são \n\n\n mais ininterruptas, e a Goroutine 2 acaba com um valor local errado no momento em que \n\n\n conclui a operação de escrita. Você tem muita sorte de que isso esteja acontecendo todas \n\n\n as vezes e você possa vê-lo. Mas normalmente, uma Data Race como essa acontece \n\n\n \u0026#34;aleatoriamente\u0026#34; e é impossível saber disso até que seja tarde demais. Felizmente, o \n\n\n Go possui um detector de corrida para ajudar a encontrar corridas de dados.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eDetecção de Corrida\u003c/h2\u003e\n \n \n \u003cp\u003e\n Existem várias maneiras de utilizar o detector de corrida. Você pode usá-lo com os comandos \n\n\n run, build e test. Se você usá-lo com o comando build, lembre-se de executar o programa. \n\n\n Dizem que um binário instrumentado pode tornar o programa mais lento em cerca de ~20%.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e$ go build -race\n$ ./example1\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A opção -race é usada para instrumentar a compilação com o detector de corrida. \n\n\n Você provavelmente a usará mais com \u0026#34;go test\u0026#34;, mas, para este exemplo, você está \n\n\n instrumentando o binário e, em seguida, executando-o.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e2021/02/01 17:30:52 logging\n2021/02/01 17:30:52 logging\n2021/02/01 17:30:52 logging\n==================\nWARNING: DATA RACE\nWrite at 0x000001278d88 by goroutine 8:\nmain.main.func1()\n /data_race/example1/example1.go:41 \u0026#43;0xa6\n\nPrevious read at 0x000001278d88 by goroutine 7:\nmain.main.func1()\n /data_race/example1/example1.go:38 \u0026#43;0x4a\n\nGoroutine 8 (running) created at:\nmain.main()\n /data_race/example1/example1.go:36 \u0026#43;0xaf\n\nGoroutine 7 (finished) created at:\nmain.main()\n /data_race/example1/example1.go:36 \u0026#43;0xaf\n==================\n2021/02/01 17:30:52 logging\nFinal Counter: 2\nFound 1 data race(s)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver que uma corrida foi detectada ao executar o programa. Isso aconteceria \n\n\n com ou sem a instrução de log inserida. Quando uma corrida é detectada, o programa \n\n\n entra em pânico e fornece esse rastreamento (trace). O rastreamento mostra onde houve \n\n\n acesso não sincronizado ao mesmo estado compartilhado, onde pelo menos um acesso foi uma operação de escrita.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Neste trace, uma Goroutine realizou uma escrita no endereço 0x000001278d88 na linha 41, \n\n\n e houve uma leitura não sincronizada no mesmo endereço por outra Goroutine na linha 38. \n\n\n Ambas as Goroutines foram criadas na linha 36.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e36 go func() {\n37 for i := 0; i \u0026lt; 2; i\u0026#43;\u0026#43; {\n38 value := counter\n39 value\u0026#43;\u0026#43;\n40 log.Println(\u0026#34;logging\u0026#34;)\n41 counter = value\n42 }\n43 wg.Done()\n44 }()\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode claramente ver a leitura e escrita não sincronizadas. Como observação adicional, \n\n\n a operação \u0026#34;plus plus\u0026#34; (++) na linha 39 também seria uma Data Race se o código \n\n\n estivesse acessando a variável de contador. A operação \u0026#34;plus plus\u0026#34;, por baixo, é uma operação \n\n\n de leitura, modificação e escrita , e o sistema operacional pode facilmente fazer uma troca \n\n\n de contexto no meio dela.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Então, como você pode corrigir o código para garantir que você remova a Data Race? \n\n\n Existem duas ferramentas que você pode usar, instruções atômicas e mutexes.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eInstruções Atômicas\u003c/h2\u003e\n \n \n \u003cp\u003e\n Instruções atômicas fornecem sincronização no nível de hardware. Devido a isso, elas são \n\n\n limitadas a palavras e meias palavras de dados. Portanto, são ótimas para contadores ou \n\n\n mecanismos de troca rápida. A API WaitGroup utiliza instruções atômicas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quais alterações você precisa fazer para aplicar instruções atômicas ao código?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar counter int32 \u0026lt;-- CHANGED\n\nfunc main() {\n const grs = 2\n\n var wg sync.WaitGroup\n wg.Add(grs)\n\n for g := 0; g \u0026lt; grs; g\u0026#43;\u0026#43; {\n go func() {\n for i := 0; i \u0026lt; 2; i\u0026#43;\u0026#43; {\n atomic.AddInt32(\u0026amp;counter, 1) \u0026lt;-- CHANGED\n }\n wg.Done()\n }()\n }\n\n wg.Wait()\n fmt.Println(\u0026#34;Counter:\u0026#34;, counter)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você só precisa fazer algumas coisas. Primeiro, mude a variável de contador para ser \n\n\n um número integer baseado em precisão. Você pode ver isso no topo da listagem de código. \n\n\n As funções atômicas só funcionam com números integers baseados em precisão. Segundo, \n\n\n remova o código de leitura, modificação e escrita manual para uma chamada a \u003ccode\u003eatomic.AddInt32\u003c/code\u003e. \n\n\n Essa única chamada lida com tudo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Todas as funções associadas ao pacote atômico recebem o endereço do estado compartilhado que \n\n\n deve ser sincronizado. A sincronização ocorre apenas no nível do endereço. Portanto, diferentes \n\n\n Goroutines chamando a mesma função, mas em um endereço diferente, não serão sincronizadas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A API para instruções atômicas se parece com isso:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc AddInt32(addr *int32, delta int32) (new int32)\nfunc AddInt64(addr *int64, delta int64) (new int64)\nfunc AddUint32(addr *uint32, delta uint32) (new uint32)\nfunc AddUint64(addr *uint64, delta uint64) (new uint64)\nfunc AddUintptr(addr *uintptr, delta uintptr) (new uintptr)\n\nfunc CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)\nfunc CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)\nfunc CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)\nfunc CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)\nfunc CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)\nfunc CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)\n\nfunc LoadInt32(addr *int32) (val int32)\nfunc LoadInt64(addr *int64) (val int64)\nfunc LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)\nfunc LoadUint32(addr *uint32) (val uint32)\nfunc LoadUint64(addr *uint64) (val uint64)\nfunc LoadUintptr(addr *uintptr) (val uintptr)\n\nfunc StoreInt32(addr *int32, val int32)\nfunc StoreInt64(addr *int64, val int64)\nfunc StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)\nfunc StoreUint32(addr *uint32, val uint32)\nfunc StoreUint64(addr *uint64, val uint64)\nfunc StoreUintptr(addr *uintptr, val uintptr)\n\nfunc SwapInt32(addr *int32, new int32) (old int32)\nfunc SwapInt64(addr *int64, new int64) (old int64)\nfunc SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)\nfunc SwapUint32(addr *uint32, new uint32) (old uint32)\nfunc SwapUint64(addr *uint64, new uint64) (old uint64)\nfunc SwapUintptr(addr *uintptr, new uintptr) (old uintptr)\n\ntype Value\n func (v *Value) Load() (x interface{})\n func (v *Value) Store(x interface{})\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver que o primeiro parâmetro é sempre o endereço de um número integer \n\n\n baseado em precisão ou um ponteiro. Também há um tipo chamado \u003ccode\u003eValue\u003c/code\u003e que fornece \n\n\n um valor síncrono com uma pequena API.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eMutexes\u003c/h2\u003e\n \n \n \u003cp\u003e\n Se você deseja manter as três linhas de código que tinha, então as instruções atômicas não \n\n\n vão funcionar. Nesse caso, o que você precisa é um mutex. Um mutex permite que você coloque \n\n\n um grupo de código em uma \u0026#34;caixa\u0026#34; para que apenas uma Goroutine por vez possa executar esse código.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar counter int\n\nfunc main() {\n const grs = 2\n\n var wg sync.WaitGroup\n wg.Add(grs)\n\n var mu sync.Mutex \u0026lt;-- CHANGED\n\n for g := 0; g \u0026lt; grs; g\u0026#43;\u0026#43; {\n go func() {\n for i := 0; i \u0026lt; 2; i\u0026#43;\u0026#43; {\n mu.Lock() \u0026lt;-- CHANGED\n {\n value := counter\n value\u0026#43;\u0026#43;\n counter = value\n }\n mu.Unlock() \u0026lt;-- CHANGED\n }\n wg.Done()\n }()\n }\n\n wg.Wait()\n fmt.Println(\u0026#34;Counter:\u0026#34;, counter)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Há várias alterações neste código em relação ao original. Você adicionou a construção da \n\n\n variável \u003ccode\u003emu\u003c/code\u003e para ser um mutex configurado com seu valor zero. Em seguida, dentro do \n\n\n loop for, você adicionou chamadas para \u003ccode\u003eLock\u003c/code\u003e e \u003ccode\u003eUnlock\u003c/code\u003e com um bloco de código artificial. \n\n\n Dentro do bloco de código, você tem o código que precisa ser sincronizado. O bloco de \n\n\n código é usado para melhorar a legibilidade.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Com este código em vigor, o scheduler permitirá que apenas uma Goroutine entre no bloco de \n\n\n código por vez. É importante entender que um mutex não é uma fila. A primeira Goroutine \n\n\n que chama \u003ccode\u003eLock\u003c/code\u003e não é necessariamente a primeira a obter o bloqueio. Existe um algoritmo \n\n\n baseado em equidade, mas isso é feito de propósito para que as pessoas não usem mutexes \n\n\n como filas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n É importante lembrar que o \u003ccode\u003eLock\u003c/code\u003e cria uma pressão de retorno, portanto, quanto mais tempo \n\n\n leva do \u003ccode\u003eLock\u003c/code\u003e até o \u003ccode\u003eUnlock\u003c/code\u003e, maior a chance de Goroutines esperando sua vez. Se você \n\n\n esquecer de chamar o \u003ccode\u003eUnlock\u003c/code\u003e, todas as Goroutines esperando entrarão em deadlock. É por \n\n\n isso que é fundamental que a chamada para \u003ccode\u003eLock\u003c/code\u003e e \u003ccode\u003eUnlock\u003c/code\u003e ocorra na mesma função. \n\n\n Certifique-se de fazer a sincronização mínima necessária no bloco de código, mas pelo menos \n\n\n o mínimo.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Este é um código muito ruim, onde alguém está tentando entrar e sair do \u003ccode\u003eLock\u003c/code\u003e tão rapidamente \n\n\n que eles realmente perdem a sincronização, e o detector de corrida nem consegue descobrir o problema.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar counter int\n\nfunc main() {\n const grs = 2\n\n var wg sync.WaitGroup\n wg.Add(grs)\n\n var mu sync.Mutex\n\n for g := 0; g \u0026lt; grs; g\u0026#43;\u0026#43; {\n go func() {\n for i := 0; i \u0026lt; 2; i\u0026#43;\u0026#43; {\n var value int\n mu.Lock() \u0026lt;-- Bad Use Of Mutex\n {\n value = counter\n }\n mu.Unlock()\n\n value\u0026#43;\u0026#43;\n\n mu.Lock() \u0026lt;-- Bad Use Of Mutex\n {\n counter = value\n }\n mu.Unlock()\n }\n wg.Done()\n }()\n }\n\n wg.Wait()\n fmt.Println(\u0026#34;Counter:\u0026#34;, counter)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Como diretriz geral, se você vir duas chamadas para \u003ccode\u003eLock\u003c/code\u003e do mesmo mutex na mesma função, \n\n\n pare a revisão de código. Provavelmente, há um erro ou uma complicação excessiva. Neste \n\n\n caso, as chamadas para leitura e escrita estão sendo sincronizadas; no entanto, duas \n\n\n Goroutines podem chegar à linha de código \u003ccode\u003evalue++\u003c/code\u003e com o mesmo valor. A corrida de \n\n\n dados ainda existe, e o detector de corrida não consegue encontrá-la.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eMutexes de Leitura/Escrita\u003c/h2\u003e\n \n \n \u003cp\u003e\n Existe um segundo tipo de mutex chamado mutex de leitura/escrita. Ele me permite separar \n\n\n os bloqueios em torno de leituras e escritas. Isso é importante, uma vez que a leitura \n\n\n de dados não representa uma ameaça, a menos que uma Goroutine esteja tentando escrever \n\n\n ao mesmo tempo. Portanto, esse tipo de mutex permite que várias Goroutines leiam a mesma \n\n\n memória ao mesmo tempo. Assim que um bloqueio de escrita é solicitado, as leituras não são \n\n\n mais permitidas, a escrita ocorre e, em seguida, as leituras podem ser retomadas.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003epackage main\n\nimport (\n \u0026#34;fmt\u0026#34;\n \u0026#34;math/rand\u0026#34;\n \u0026#34;sync\u0026#34;\n \u0026#34;time\u0026#34;\n)\n\nvar data []string\nvar rwMutex sync.RWMutex\n\nfunc main() {\n var wg sync.WaitGroup\n wg.Add(1)\n\n go func() {\n for i := 0; i \u0026lt; 10; i\u0026#43;\u0026#43; {\n writer(i)\n }\n wg.Done()\n }()\n\n for i := 0; i \u0026lt; 8; i\u0026#43;\u0026#43; {\n go func(id int) {\n for {\n reader(id)\n }\n }(i)\n }\n\n wg.Wait()\n fmt.Println(\u0026#34;Program Complete\u0026#34;)\n}\n\nfunc writer(i int) {\n rwMutex.Lock()\n {\n time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)\n fmt.Println(\u0026#34;****\u0026gt; : Performing Write\u0026#34;)\n data = append(data, fmt.Sprintf(\u0026#34;String: %d\u0026#34;, i))\n }\n rwMutex.Unlock()\n}\n\nfunc reader(id int) {\n rwMutex.RLock()\n {\n time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)\n fmt.Printf(\u0026#34;%d : Performing Read : Length[%d]\\n\u0026#34;, id, len(data))\n }\n rwMutex.RUnlock()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver o uso de um mutex de leitura/escrita onde existem 8 Goroutines lendo o \n\n\n comprimento de um slice com um atraso de 10 milissegundos entre elas, e 1 Goroutine \n\n\n acordando dentro de 100 milissegundos para anexar um valor (escrever) no slice.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A chave está na implementação das funções de escrita e leitura. Observe como você usa \n\n\n \u003ccode\u003eLock\u003c/code\u003e para o escritor e \u003ccode\u003eRLock\u003c/code\u003e para o leitor. Um dos maiores erros que você pode \n\n\n cometer é misturar chamadas de \u003ccode\u003eUnlock\u003c/code\u003e com a versão errada. Ter um \u003ccode\u003eLock\u003c/code\u003e com um \n\n\n \u003ccode\u003eRUnlock\u003c/code\u003e nunca terminará bem.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e7 : Performing Read : Length[0]\n5 : Performing Read : Length[0]\n0 : Performing Read : Length[0]\n3 : Performing Read : Length[0]\n7 : Performing Read : Length[0]\n2 : Performing Read : Length[0]\n1 : Performing Read : Length[0]\n****\u0026gt; : Performing Write\n0 : Performing Read : Length[1]\n5 : Performing Read : Length[1]\n3 : Performing Read : Length[1]\n6 : Performing Read : Length[1]\n7 : Performing Read : Length[1]\n4 : Performing Read : Length[1]\n1 : Performing Read : Length[1]\n2 : Performing Read : Length[1]\n****\u0026gt; : Performing Write\n7 : Performing Read : Length[2]\n1 : Performing Read : Length[2]\n3 : Performing Read : Length[2]\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A saída mostra como várias Goroutines estão lendo ao mesmo tempo, mas todas as leituras param quando a escrita ocorre.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eAs Goroutines precisam ser coordenadas e sincronizadas.\u003c/li\u003e\n \n \u003cli\u003eQuando duas ou mais Goroutines tentam acessar o mesmo recurso, temos uma Data Race.\u003c/li\u003e\n \n \u003cli\u003eFunções atômicas e mutexes podem fornecer o suporte de que precisamos.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eCoerência de Cache e Falso Compartilhamento\u003c/h2\u003e\n \n \n \u003cp\u003e\n Este conteúdo é fornecido por Scott Meyers de sua palestra em 2014 na Dive.:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003ca href=\"https://youtu.be/WDIkqP4JbkE?t=1809\" target=\"_blank\"\u003eCPU Caches and Why You Care (30:09-38:30)\u003c/a\u003e \n\n\n \u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/go/testing/benchmarks/falseshare/README.md\" target=\"_blank\"\u003eCode Example\u003c/a\u003e\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/figure1_data_race.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/figure1_data_race.png\"\u003e\n \u003c/a\u003e\n\n\n \u003ch2\u003eNotas sobre Coerência de Cache e Falso Compartilhamento\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eO acesso à memória por threads é importante.\u003c/li\u003e\n \n \u003cli\u003eSe seu algoritmo não está escalando, procure por problemas de falso compartilhamento.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.drdobbs.com/parallel/eliminate-false-sharing/217500206\" target=\"_blank\"\u003eEliminate False Sharing\u003c/a\u003e - Herb Sutter \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/ref/mem\" target=\"_blank\"\u003eThe Go Memory Model\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/race-detector\" target=\"_blank\"\u003eIntroducing the Go Race Detector\u003c/a\u003e - Dmitry Vyukov and Andrew Gerrand \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/09/detecting-race-conditions-with-go.html\" target=\"_blank\"\u003eDetecting Race Conditions With Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/doc/articles/race_detector.html\" target=\"_blank\"\u003eData Race Detector\u003c/a\u003e \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// YOU NEED TO RUN THIS EXAMPLE OUTSIDE OF THE TOUR\n// go build -race or go run main.go -race\n\n// Sample program to show how to create race conditions in\n// our programs. We don't want to do this.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n// counter is a variable incremented by all goroutines.\nvar counter int\n\nfunc main() {\n\n\t// Number of goroutines to use.\n\tconst grs = 2\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(grs)\n\n\t// Create two goroutines.\n\tfor g := 0; g \u003c grs; g++ {\n\t\tgo func() {\n\t\t\tfor i := 0; i \u003c 2; i++ {\n\n\t\t\t\t// Capture the value of Counter.\n\t\t\t\tvalue := counter\n\n\t\t\t\t// Increment our local value of Counter.\n\t\t\t\tvalue++\n\n\t\t\t\t// Store the value back into Counter.\n\t\t\t\tcounter = value\n\t\t\t}\n\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// Wait for the goroutines to finish.\n\twg.Wait()\n\tfmt.Println(\"Final Counter:\", counter)\n}\n\n/*\n==================\nWARNING: DATA RACE\nRead at 0x0000011a5118 by goroutine 7:\n main.main.func1()\n example1.go:34 +0x4e\n\nPrevious write at 0x0000011a5118 by goroutine 6:\n main.main.func1()\n example1.go:40 +0x6d\n\nGoroutine 7 (running) created at:\n main.main()\n example1.go:44 +0xc3\n\nGoroutine 6 (finished) created at:\n main.main()\n example1.go:44 +0xc3\n==================\nFinal Counter: 4\nFound 1 data race(s)\n*/\n","Hash":"uoHh7aa9CUuwaQNG10SqmntY5i8="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// YOU NEED TO RUN THIS EXAMPLE OUTSIDE OF THE TOUR\n// go build -race or go run main.go -race\n\n// Sample program to show how to use the atomic package to\n// provide safe access to numeric types.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\n// counter is a variable incremented by all goroutines.\nvar counter int64\n\nfunc main() {\n\n\t// Number of goroutines to use.\n\tconst grs = 2\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(grs)\n\n\t// Create two goroutines.\n\tfor g := 0; g \u003c grs; g++ {\n\t\tgo func() {\n\t\t\tfor i := 0; i \u003c 2; i++ {\n\t\t\t\tatomic.AddInt64(\u0026counter, 1)\n\t\t\t}\n\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// Wait for the goroutines to finish.\n\twg.Wait()\n\n\t// Display the final value.\n\tfmt.Println(\"Final Counter:\", counter)\n}\n","Hash":"Jq+0MDW2w9f8gLbu3z8A2Bnu3Q0="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use a mutex to define critical\n// sections of code that need synchronous access.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n// counter is a variable incremented by all goroutines.\nvar counter int\n\n// mutex is used to define a critical section of code.\nvar mutex sync.Mutex\n\nfunc main() {\n\n\t// Number of goroutines to use.\n\tconst grs = 2\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(grs)\n\n\t// Create two goroutines.\n\tfor g := 0; g \u003c grs; g++ {\n\t\tgo func() {\n\t\t\tfor i := 0; i \u003c 2; i++ {\n\n\t\t\t\t// Only allow one goroutine through this critical section at a time.\n\t\t\t\tmutex.Lock()\n\t\t\t\t{\n\t\t\t\t\t// Capture the value of counter.\n\t\t\t\t\tvalue := counter\n\n\t\t\t\t\t// Increment our local value of counter.\n\t\t\t\t\tvalue++\n\n\t\t\t\t\t// Store the value back into counter.\n\t\t\t\t\tcounter = value\n\t\t\t\t}\n\t\t\t\tmutex.Unlock()\n\t\t\t\t// Release the lock and allow any waiting goroutine through.\n\t\t\t}\n\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// Wait for the goroutines to finish.\n\twg.Wait()\n\tfmt.Printf(\"Final Counter: %d\\n\", counter)\n}\n","Hash":"DqmHWtidPhKct3YXM7sXPNIInHA="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to use a read/write mutex to define critical\n// sections of code that needs synchronous access.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// data is a slice that will be shared.\nvar data []string\n\n// rwMutex is used to define a critical section of code.\nvar rwMutex sync.RWMutex\n\n// Number of reads occurring at ay given time.\nvar readCount int64\n\nfunc main() {\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\n\t// Create a writer goroutine.\n\tgo func() {\n\t\tfor i := 0; i \u003c 10; i++ {\n\t\t\twriter(i)\n\t\t}\n\t\twg.Done()\n\t}()\n\n\t// Create eight reader goroutines.\n\tfor i := 0; i \u003c 8; i++ {\n\t\tgo func(id int) {\n\t\t\tfor {\n\t\t\t\treader(id)\n\t\t\t}\n\t\t}(i)\n\t}\n\n\t// Wait for the write goroutine to finish.\n\twg.Wait()\n\tfmt.Println(\"Program Complete\")\n}\n\n// writer adds a new string to the slice in random intervals.\nfunc writer(i int) {\n\n\t// Only allow one goroutine to read/write to the slice at a time.\n\trwMutex.Lock()\n\t{\n\t\t// Capture the current read count.\n\t\t// Keep this safe though we can due without this call.\n\t\trc := atomic.LoadInt64(\u0026readCount)\n\n\t\t// Perform some work since we have a full lock.\n\t\ttime.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)\n\t\tfmt.Printf(\"****\u003e : Performing Write : RCount[%d]\\n\", rc)\n\t\tdata = append(data, fmt.Sprintf(\"String: %d\", i))\n\t}\n\trwMutex.Unlock()\n\t// Release the lock.\n}\n\n// reader wakes up and iterates over the data slice.\nfunc reader(id int) {\n\n\t// Any goroutine can read when no write operation is taking place.\n\trwMutex.RLock()\n\t{\n\t\t// Increment the read count value by 1.\n\t\trc := atomic.AddInt64(\u0026readCount, 1)\n\n\t\t// Perform some read work and display values.\n\t\ttime.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)\n\t\tfmt.Printf(\"%d : Performing Read : Length[%d] RCount[%d]\\n\", id, len(data), rc)\n\n\t\t// Decrement the read count value by 1.\n\t\tatomic.AddInt64(\u0026readCount, -1)\n\t}\n\trwMutex.RUnlock()\n\t// Release the read lock.\n}\n","Hash":"giFOhX7bsf3OftNIhBQsqHCWxwE="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how maps are not safe for concurrent use by default.\n// The runtime will detect concurrent writes and panic.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n// scores holds values incremented by multiple goroutines.\nvar scores = make(map[string]int)\n\nfunc main() {\n\tvar wg sync.WaitGroup\n\twg.Add(2)\n\n\tgo func() {\n\t\tfor i := 0; i \u003c 1000; i++ {\n\t\t\tscores[\"A\"]++\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tgo func() {\n\t\tfor i := 0; i \u003c 1000; i++ {\n\t\t\tscores[\"B\"]++\n\t\t}\n\t\twg.Done()\n\t}()\n\n\twg.Wait()\n\tfmt.Println(\"Final scores:\", scores)\n}\n","Hash":"R4pc+mOl/3CtmUGdjOyerVHmNsg="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show a more complicated race condition using\n// an interface value. This produces a read to an interface value after\n// a partial write.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n)\n\n// Speaker allows for speaking behavior.\ntype Speaker interface {\n\tSpeak() bool\n}\n\n// Ben is a person who can speak.\ntype Ben struct {\n\tname string\n}\n\n// Speak allows Ben to say hello. It returns false if the method is\n// called through the interface value after a partial write.\nfunc (b *Ben) Speak() bool {\n\tif b.name != \"Ben\" {\n\t\tfmt.Printf(\"Ben says, \\\"Hello my name is %s\\\"\\n\", b.name)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Jerry is a person who can speak.\ntype Jerry struct {\n\tname string\n}\n\n// Speak allows Jerry to say hello. It returns false if the method is\n// called through the interface value after a partial write.\nfunc (j *Jerry) Speak() bool {\n\tif j.name != \"Jerry\" {\n\t\tfmt.Printf(\"Jerry says, \\\"Hello my name is %s\\\"\\n\", j.name)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc main() {\n\n\t// Create values of type Ben and Jerry.\n\tben := Ben{\"Ben\"}\n\tjerry := Jerry{\"Jerry\"}\n\n\t// Assign the pointer to the Ben value to the interface value.\n\tperson := Speaker(\u0026ben)\n\n\t// Have a goroutine constantly assign the pointer of\n\t// the Ben value to the interface and then Speak.\n\tgo func() {\n\t\tfor {\n\t\t\tperson = \u0026ben\n\t\t\tif !person.Speak() {\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Have a goroutine constantly assign the pointer of\n\t// the Jerry value to the interface and then Speak.\n\tgo func() {\n\t\tfor {\n\t\t\tperson = \u0026jerry\n\t\t\tif !person.Speak() {\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Just hold main from returning. The data race will\n\t// cause the program to exit.\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\twg.Wait()\n}\n","Hash":"xT1O2rUKBmi1J317ugjfo91Y+ew="}]},{"Title":"exercícios","Content":"\n \u003ch2\u003eexercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Dado o programa a seguir, use o detector de corrida (race detector) para encontrar e corrigir a Data Race.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Fix the race condition in this program.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\n// numbers maintains a set of random numbers.\nvar numbers []int\n\nfunc main() {\n\n\t// Number of goroutines to use.\n\tconst grs = 3\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(grs)\n\n\t// Create three goroutines to generate random numbers.\n\tfor i := 0; i \u003c grs; i++ {\n\t\tgo func() {\n\t\t\trandom(10)\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// Wait for all the goroutines to finish.\n\twg.Wait()\n\n\t// Display the set of random numbers.\n\tfor i, number := range numbers {\n\t\tfmt.Println(i, number)\n\t}\n}\n\n// random generates random numbers and stores them into a slice.\nfunc random(amount int) {\n\n\t// Generate as many random numbers as specified.\n\tfor i := 0; i \u003c amount; i++ {\n\t\tn := rand.Intn(100)\n\t\tnumbers = append(numbers, n)\n\t}\n}\n","Hash":"a0Ebkx0381HuUS6U/zEkOUpldoI="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Answer for exercise 1 of Race Conditions.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\n// numbers maintains a set of random numbers.\nvar numbers []int\n\n// mutex will help protect the slice.\nvar mutex sync.Mutex\n\n// main is the entry point for the application.\nfunc main() {\n\t// Number of goroutines to use.\n\tconst grs = 3\n\n\t// wg is used to manage concurrency.\n\tvar wg sync.WaitGroup\n\twg.Add(grs)\n\n\t// Create three goroutines to generate random numbers.\n\tfor i := 0; i \u003c grs; i++ {\n\t\tgo func() {\n\t\t\trandom(10)\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// Wait for all the goroutines to finish.\n\twg.Wait()\n\n\t// Display the set of random numbers.\n\tfor i, number := range numbers {\n\t\tfmt.Println(i, number)\n\t}\n}\n\n// random generates random numbers and stores them into a slice.\nfunc random(amount int) {\n\t// Generate as many random numbers as specified.\n\tfor i := 0; i \u003c amount; i++ {\n\t\tn := rand.Intn(100)\n\n\t\t// Protect this append to keep access safe.\n\t\tmutex.Lock()\n\t\t{\n\t\t\tnumbers = append(numbers, n)\n\t\t}\n\t\tmutex.Unlock()\n\t}\n}\n","Hash":"jwVW1FIbUTkDCvNH9AwdZmRK40g="}]}]} ,"generics-multi-type-params":{"Title":"Parâmetros Multitipo","Description":"Você não está restrito a usar somente um tipo genérico por vez.","Pages":[{"Title":"Generics - Parâmetros Multitipo","Content":"\n \u003ch2\u003eGenerics - Parâmetros Multitipo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Você não está restrito a usar somente um tipo genérico por vez.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Generics, que mostra todos os\n\n\n exemplos que estão nesta seção do Tour.\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Função Print\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicação\u003c/h2\u003e\n \n \n \u003cpre class=\"codeblock\"\u003efunc Print[L any, V fmt.Stringer](labels []L, vals []V) {\n for i, v := range vals {\n fmt.Println(labels[i], v.String())\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função Print aceita uma coleção de algum tipo L e uma coleção de algum tipo V.\n\n\n O tipo L pode ser qualquer coisa, mas o tipo V é limitado à valores que possuem\n\n\n o método String. A coleção de algum tipo V é iterada e impressa com seu correspondente\n\n\n rótulo da coleção do tipo L.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O nome do tipo genérico pode ser qualquer coisa. A convenção de nomenclatura para\n\n\n tipos genéricos é algo que precisa ser definido melhor para melhores práticas.\n\n\n Por enquanto, tente limitar-se a uma única letra maiúscula quando isso funcionar\n\n\n para a legibilidade.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to write a generic functions that take multiple\n// generic parameters.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n// Print is a function that accepts a slice of some type L and a slice of some\n// type V (to be determined later). Each value of the labels slice will be\n// joined with the vals slice at the same index position. This code shows how\n// the generics type list can contain more than just one generic type and have\n// different constraints for each.\n\nfunc Print[L any, V fmt.Stringer](labels []L, vals []V) {\n\tfor i, v := range vals {\n\t\tfmt.Println(labels[i], v.String())\n\t}\n}\n\n// This code defines a concrete type named user that implements the fmt.Stringer\n// interface. The String method just returns the name field from the user type.\n\ntype user struct {\n\tname string\n}\n\nfunc (u user) String() string {\n\treturn u.name\n}\n\n// =============================================================================\n\nfunc main() {\n\tlabels := []int{1, 2, 3}\n\tnames := []user{{\"bill\"}, {\"jill\"}, {\"joan\"}}\n\n\tPrint(labels, names)\n}\n","Hash":"Qh17LMhal5YGOZWJi2CXJnPQDfk="}]}]} ,"generics-slice-constraints":{"Title":"Restrições de Slice","Description":"Pode haver momentos em que você precisa restringir o tipo generic a ser apenas um slice.","Pages":[{"Title":"Generics - Restrições de Slice","Content":"\n \u003ch2\u003eGenerics - Restrições de Slice\u003c/h2\u003e\n \n \n \u003cp\u003e\n Pode haver momentos em que você precisa restringir o tipo generic a ser apenas um slice.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVídeo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Generics, que percorre todos os exemplos \n\n\n desta seção do Tour (vídeo em Inglês).\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Função Operate\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicação\u003c/h2\u003e\n \n \n \u003cp\u003e\n Aqui o usuário definiu o tipo Numbers que no fundo é um slice do tipo integers. \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Numbers []int\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O compilador permite que você converta variáveis baseadas em um slice de \n\n\n integers para variáveis do tipo Numbers. Isso geralmente é bom e é o que \n\n\n você deseja. Devido a essa funcionalidade, você pode escrever uma função \n\n\n generic que pode operar em um slice, respeitando o tipo subjacente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype operateFunc[T any] func(t T) T\n\nfunc operate[T any](slice []T, fn operateFunc[T]) []T {\n ret := make([]T, len(slice))\n for i, v := range slice {\n ret[i] = fn(v)\n }\n \n return ret\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui, a função operate declara um tipo generic T que pode ser qualquer coisa. Esse tipo \n\n\n é usado para declarar um parâmetro chamado slice que aceita um slice desse mesmo tipo T. \n\n\n A função também aceita uma função generic do mesmo tipo T e também retorna um slice de T.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Numbers []int\n\nfunc Double(n Numbers) Numbers {\n fn := func(n int) int {\n return 2 * n\n }\n\n numbers := operate(n, fn)\n fmt.Printf(\u0026#34;%T\u0026#34;, numbers)\n return numbers\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e[]int\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função Double aceita um valor do tipo Numbers e passa esse valor para a função operate. \n\n\n Neste caso, o compilador utiliza o tipo subjacente para o tipo T e o valor Numbers pode \n\n\n ser passado para a função. No entanto, o que é retornado é um slice do tipo int, como \n\n\n visto no resultado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se você precisa garantir que apenas um valor Numbers possa ser passado e retornado \n\n\n pela função operate, você pode fazer as seguintes alterações.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Slice[T any] interface {\n ~ []T\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Essa interface declara uma restrição para restringir um tipo generic a um slice real \n\n\n de algum tipo T. O uso do elemento de aproximação ~ restringe a todos os tipos cujo tipo \n\n\n subjacente seja T. Com essa interface, você pode alterar a função operate.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype operateFunc[T any] func(t T) T\ntype Slice[T any] interface {\n ~ []T\n}\n\n// func operate[T any](slice []T, fn operateFunc[T]) []T {\n// ret := make([]T, len(slice))\n// for i, v := range slice {\n// ret[i] = fn(v)\n// }\n// return ret\n// }\n\nfunc operate[S Slice[T], T any](slice S, fn operateFunc[T]) S {\n ret := make(S, len(slice))\n for i, v := range slice {\n ret[i] = fn(v)\n }\n \n return ret\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Agora, altere a função operate para declarar dois tipos genéricos. O tipo S que representa \n\n\n um valor de slice de algum tipo T e T, que é um tipo que pode ser qualquer coisa. A função \n\n\n retorna um valor do tipo S.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Numbers []int\n\nfunc Double(n Numbers) Numbers {\n fn := func(n int) int {\n return 2 * n\n }\n\n numbers := operate(n, fn)\n fmt.Printf(\u0026#34;%T\u0026#34;, numbers)\n \n return numbers\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003emain.Numbers\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Desta vez, quando você passa o valor Numbers para a função operate, o slice que é retornado é \n\n\n do tipo Numbers. O tipo subjacente é ignorado e o tipo definido pelo usuário é respeitado.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to define slice based constraints.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n// operateFunc defines a function type that takes a value of some type T and\n// returns a value of the same type T (to be determined later).\n//\n// Slice defines a constraint that the data is a slice of some type T (to be\n// determined later).\n\ntype operateFunc[T any] func(t T) T\n\ntype Slice[T any] interface {\n\t~[]T\n}\n\n// When it's important that the slice being passed in is exactly the same\n// as the slice being returned, use a slice constraint. This ensures that the\n// result slice S is the same as the incoming slice S.\n\nfunc operate[S Slice[T], T any](slice S, fn operateFunc[T]) S {\n\tret := make(S, len(slice))\n\tfor i, v := range slice {\n\t\tret[i] = fn(v)\n\t}\n\treturn ret\n}\n\n// If you don't care about the constraint defined above, then operate2 provides\n// a simpler form. Operate2 still works because you can assign a slice of some\n// type T to the input and output arguments. However, the concrete types of the\n// input and output arguments will be based on the underlying types. In this\n// case not a slice of Numbers, but a slice of integers. This is not the case\n// with operate function above.\n\nfunc operate2[T any](slice []T, fn operateFunc[T]) []T {\n\tret := make([]T, len(slice))\n\tfor i, v := range slice {\n\t\tret[i] = fn(v)\n\t}\n\treturn ret\n}\n\n// I suspect most of the time operate2 is what you want: it's simpler, and more\n// flexible: You can always assign a []int back to a Numbers variable and vice\n// versa. But if you need to preserve that incoming type in the result for some\n// reason, you will need to use operate.\n\n// =============================================================================\n\n// This code defines a named type that is based on a slice of integers. An\n// integer is the underlying type.\n//\n// Double is a function that takes a value of type Numbers, multiplies each\n// value in the underlying integer slice and returns that new Numbers value.\n//\n// Line 73 is commented out because the compiler is smart enough to infer the\n// types for S and T. The commented code shows the types being inferred.\n//\n// operate2 is not used in the example.\n\ntype Numbers []int\n\nfunc DoubleUnderlying(n Numbers) Numbers {\n\tfn := func(n int) int {\n\t\treturn 2 * n\n\t}\n\n\tnumbers := operate2(n, fn)\n\tfmt.Printf(\"%T\", numbers)\n\treturn numbers\n}\n\nfunc DoubleUserDefined(n Numbers) Numbers {\n\tfn := func(n int) int {\n\t\treturn 2 * n\n\t}\n\n\tnumbers := operate(n, fn)\n\tfmt.Printf(\"%T\", numbers)\n\treturn numbers\n}\n\n// =============================================================================\n\nfunc main() {\n\tn := Numbers{10, 20, 30, 40, 50}\n\tfmt.Println(n)\n\n\tn = DoubleUnderlying(n)\n\tfmt.Println(n)\n\n\tn = DoubleUserDefined(n)\n\tfmt.Println(n)\n}\n","Hash":"N5/uaH85IbojxXFef5MfUoRu7XU="}]}]} ,"methods":{"Title":"Métodos","Description":"Uma função é chamada de método quando essa função tem um receiver declarado.","Pages":[{"Title":"Métodos","Content":"\n \u003ch2\u003eMétodos\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Uma função é chamada de método quando essa função tem um receiver declarado. O\n\n\n receiver é o parâmetro que é declarado entre a palavra-chave func e o nome da\n\n\n função.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declaração e comportamento do receiver\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Métodos em tipos nomeados\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Variáveis de função/método\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Tipos de função\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Semântica de valor e ponteiro\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eDeclarações de Método\u003c/h2\u003e\n \n \n \u003cp\u003e\n Existem dois tipos de receivers, receivers de valor para implementar a semântica\n\n\n de valor e receivers de ponteiro para implementar a semântica de ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n email string\n}\n\nfunc (u user) notify() {\n fmt.Printf(\u0026#34;Sending User Email To %s\u0026lt;%s\u0026gt;\\n\u0026#34;, u.name, u.email)\n}\n\nfunc (u *user) changeEmail(email string) {\n u.email = email\n fmt.Printf(\u0026#34;Changed User Email To %s\\n\u0026#34;, email)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função notify é implementada com um receiver de valor. Isso significa que o\n\n\n método opera sob semântica de valor e operará em sua própria cópia do valor usado\n\n\n para fazer a chamada.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A função changeEmail é implementada com um receiver de ponteiro. Isso significa\n\n\n que o método opera sob semântica de ponteiro e operará com acesso compartilhado\n\n\n ao valor usado para fazer a chamada.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Fora algumas exceções, um conjunto de métodos de um tipo não deve\n\n\n conter uma mistura de receivers de valor e ponteiro. A consistência semântica\n\n\n dos dados é extremamente importante e isso inclui a declaração de métodos.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eChamadas de Método\u003c/h2\u003e\n \n \n \u003cp\u003e\n Ao fazer uma chamada de método, o compilador não se importa se o valor usado\n\n\n para fazer a chamada corresponde exatamente à semântica dos dados do receiver.\n\n\n O compilador só quer um valor ou ponteiro do mesmo tipo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ebill := user{\u0026#34;Bill\u0026#34;, \u0026#34;bill@email.com\u0026#34;}\nbill.notify()\nbill.changeEmail(\u0026#34;bill@hotmail.com\u0026#34;)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode ver que um valor do tipo user é construído e atribuído à variável\n\n\n bill. No caso da chamada do notify, a variável bill corresponde ao tipo receiver\n\n\n que é um receiver de valor. No caso da chamada do changeEmail, a variável bill\n\n\n não corresponde ao tipo de receiver que é um receiver de ponteiro. Entretanto,\n\n\n o compilador aceita a chamada do método e compartilha a variável bill com o\n\n\n método. Go se ajustará para fazer a chamada.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Isso funciona da mesma forma quando a variável usada para fazer a chamada é uma\n\n\n variável de ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ebill := \u0026amp;user{\u0026#34;Bill\u0026#34;, \u0026#34;bill@email.com\u0026#34;}\nbill.notify()\nbill.changeEmail(\u0026#34;bill@hotmail.com\u0026#34;)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste caso, a variável bill é uma variável de ponteiro para um valor do tipo user.\n\n\n Mais uma vez, Go se ajusta para fazer a chamada de método ao chamar o método notify.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se Go não se ajustasse, então isso é o que você teria que fazer para realizar as mesmas\n\n\n chamadas de método.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ebill := user{\u0026#34;Bill\u0026#34;, \u0026#34;bill@email.com\u0026#34;}\n(\u0026amp;bill).changeEmail(\u0026#34;bill@hotmail.com\u0026#34;)\n\nbill := \u0026amp;user{\u0026#34;Bill\u0026#34;, \u0026#34;bill@email.com\u0026#34;}\n(*bill).notify()\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Fico feliz que você não precise fazer isso para fazer chamadas de método em Go.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eOrientação de Semântica de Dados Para Tipos Internos\u003c/h2\u003e\n \n \n \u003cp\u003e\n Como uma orientação, se os dados com os quais estou trabalhando forem um tipo\n\n\n interno (slice, map, channel, function, interface), use a semântica de valor\n\n\n para mover os dados pelo programa. Isso inclui declarar campos em um tipo.\n\n\n No entanto, quando estou lendo e escrevendo, você precisa se lembrar que estou\n\n\n usando a semântica de ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype IP []byte\ntype IPMask []byte\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esse tipos são declarados no pacote net que faz parte da biblioteca padrão.\n\n\n Eles são declarados com um underlying type que é uma slice de bytes. Por causa\n\n\n disso, esses tipos seguem as guidelines de tipos internos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (ip IP) Mask(mask IPMask) IP {\n if len(mask) == IPv6len \u0026amp;\u0026amp; len(ip) == IPv4len \u0026amp;\u0026amp; allFF(mask[:12]) {\n mask = mask[12:]\n }\n if len(mask) == IPv4len \u0026amp;\u0026amp; len(ip) == IPv6len \u0026amp;\u0026amp;\n bytesEqual(ip[:12], v4InV6Prefix) {\n ip = ip[12:]\n }\n n := len(ip)\n if n != len(mask) {\n return nil\n }\n out := make(IP, n)\n for i := 0; i \u0026lt; n; i\u0026#43;\u0026#43; {\n out[i] = ip[i] \u0026amp; mask[i]\n }\n return out\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Com o método Mask, a semântica de valor está em jogo para o receiver, parâmetro e\n\n\n para o argumento de retorno. Este método aceita sua própria cópia de um valor Mask,\n\n\n ele modifica esse valor e então retorna uma cópia da mutação. Este método está usando\n\n\n semântica de valor para mutação. Isso não é um acidente ou aleatório.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Uma função pode decidir quais entradas e saídas de dados são necessárias. O que\n\n\n ela não pode decidir é a semântica dos dados sobre como os dados entram ou saem.\n\n\n Os dados orientam essa decisão e a função deve estar em conformidade. É por isso\n\n\n que Mask implementa a API de mutação utilizando semântica de valor. Isso deve\n\n\n respeitar a forma como uma slice é projetada para ser movida pelo programa.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc ipEmptyString(ip IP) string {\n if len(ip) == 0 {\n return \u0026#34;\u0026#34;\n }\n return ip.String()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função \u003ccode\u003eipEmptyString\u003c/code\u003e também usa semântica de valor para entrada e saída.\n\n\n Esta função aceita sua própria cópia de um valor IP e retorna um valor string. Não\n\n\n há uso de semântica de ponteiro porque os dados ditam a semântica dos dados e não\n\n\n a função.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Uma exceção ao uso da semântica de valor é quando você precisa compartilhar uma\n\n\n slice ou map com uma função que executa unmarshaling ou decoding.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eOrientação de Semântica de Dados Para Tipos Struct\u003c/h2\u003e\n \n \n \u003cp\u003e\n Como uma orientação, se os dados com os quais estou trabalhando são um tipo struct,\n\n\n então você deve pensar sobre o que os dados representam para tomar uma decisão.\n\n\n Uma boa regra geral é perguntar se a struct representa dados ou uma API. Se a struct\n\n\n representa dados, use a semântica de valor. Se a struct representa uma API, use\n\n\n a semântica de ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Time struct {\n sec int64\n nsec int32\n loc *Location\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui está a struct Time do pacote time. Se você considerar que Time representa\n\n\n dados, a semântica de valor deve ser usada para essa struct.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Ao examinar uma base de código existente e desejar saber qual era a semântica de\n\n\n dados escolhida, procure por uma factory function. O tipo de retorno da factory\n\n\n function deve ditar a semântica de dados escolhida pelo desenvolvedor.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Now() Time {\n sec, nsec := now()\n return Time{sec \u0026#43; unixToInternal, nsec, Local}\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Now é a factory function para construir valores Time. Veja o retorno, está usando\n\n\n semântica de valor. Isso indica que você deve usar semântica de valor para valores\n\n\n Time, o que significa que cada função obtém sua própria cópia do valor Time e os\n\n\n campos em uma struct devem ser declarados como valores do tipo Time.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (t Time) Add(d Duration) Time {\n t.sec \u0026#43;= int64(d / 1e9)\n nsec := int32(t.nsec) \u0026#43; int32(d%1e9)\n if nsec \u0026gt;= 1e9 {\n t.sec\u0026#43;\u0026#43;\n nsec -= 1e9\n } else if nsec \u0026lt; 0 {\n t.sec--\n nsec \u0026#43;= 1e9\n }\n t.nsec = nsec\n return t\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Add é um método que precisa realizar uma operação de mutação. Se você olhar com\n\n\n atenção, verá que a função semântica de valor para mutação. O método Add obtém\n\n\n sua própria cópia do valor Time usado para fazer a chamada, ele modifica sua própria\n\n\n cópia e retorna uma cópia para o chamador. Mais uma vez, esta é a maneira mais\n\n\n segura de realizar uma operação de mutação.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc div(t Time, d Duration) (qmod2 int, r Duration) {}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui está outro exemplo onde a função div aceita um valor do tipo Time e Duration\n\n\n (int64) e retorna valores do tipo int e Duration. Semântica de valor para o tipo\n\n\n Time e para todos os tipos built-in. Duration tem um underlying type de int64.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (t *Time) UnmarshalBinary(data []byte) error {}\nfunc (t *Time) GobDecode(data []byte) error {}\nfunc (t *Time) UnmarshalJSON(data []byte) error {}\nfunc (t *Time) UnmarshalText(data []byte) error {}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esses quatro métodos do pacote Time parecem quebrar as regras de consistência da \n\n\n semântica de dados. Eles estão usando semântica de ponteiro, por quê? Porque eles\n\n\n estão implementando uma interface onde a assinatura do método está bloqueada. Como\n\n\n a implementação requer uma mutação, a semântica de ponteiro é a única escolha.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Aqui está uma orientação: Se a semântica de valor estiver em jogo, você pode mudar\n\n\n para a semântica de ponteiro para algumas funções, desde que não permita que os\n\n\n dados na cadeia de chamadas restante voltem para a semântica de valor. Depois\n\n\n de mudar para semântica de ponteiro, todas as chamadas futuras a partir desse\n\n\n ponto precisarão seguir a semântica de ponteiro. Você nunca, jamais, pode mudar\n\n\n de ponteiro para valor. Nunca é seguro fazer uma cópia de um valor para o qual\n\n\n um ponteiro aponta.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Open(name string) (file *File, err error) {\n return OpenFile(name, O_RDONLY, 0)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função Open do pacote os mostra que ao usar um valor do tipo File, a semântica\n\n\n de ponteiro está em jogo. Valores File precisam ser compartilhados e nunca devem\n\n\n ser copiados.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (f *File) Chdir() error {\n if f == nil {\n return ErrInvalid\n }\n if e := syscall.Fchdir(f.fd); e != nil {\n return \u0026amp;PathError{\u0026#34;chdir\u0026#34;, f.name, e}\n }\n return nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O método Chdir está usando a receiver de ponteiro, apesar disso esse método\n\n\n não altera o valor de File. Isso ocorre porque os valores File precisam ser\n\n\n compartilhados e não podem ser copiados.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc epipecheck(file *File, e error) {\n if e == syscall.EPIPE {\n if atomic.AddInt32(\u0026amp;file.nepipe, 1) \u0026gt;= 10 {\n sigpipe()\n }\n } else {\n atomic.StoreInt32(\u0026amp;file.nepipe, 0)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função epipecheck também aceita valores File usando semântica de ponteiro.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eMétodos São Apenas Funções\u003c/h2\u003e\n \n \n \u003cp\u003e\n Métodos são, na verdade, apenas funções que fornecem um syntactic sugar para\n\n\n fornecer a capacidade dos dados exibirem comportamento.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype data struct {\n name string\n age int\n}\n\nfunc (d data) displayName() {\n fmt.Println(\u0026#34;My Name Is\u0026#34;, d.name)\n}\n\nfunc (d *data) setAge(age int) {\n d.age = age\n fmt.Println(d.name, \u0026#34;Is Age\u0026#34;, d.age)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Um tipo e dois métodos são declarados. O método displayName está usando\n\n\n semântica de valor e setAge está usando semântica de ponteiro.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nota: Não implemente setters e getters em Go. Estas não são APIs com propósito\n\n\n e nestes casos é melhor exportar esses campos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ed := data{\n name: \u0026#34;Bill\u0026#34;,\n}\n\nd.displayName()\nd.setAge(21)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Um valor do tipo data é construído e chamadas de métodos são feitas.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003edata.displayName(d)\n(*data).setAge(\u0026amp;d, 21)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Uma vez que métodos são apenas funções com syntactic sugar, os métodos podem\n\n\n ser executados como funções. Você pode ver que o receiver é realmente um parâmetro,\n\n\n é o primeiro parâmetro. Quando você chama um método o compilador o converte em\n\n\n uma chamada de função por baixo dos panos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nota: Não execute métodos dessa forma, mas você poderá ver esta sintaxe em\n\n\n mensagens de ferramentas.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eConheça o Comportamento do Código\u003c/h2\u003e\n \n \n \u003cp\u003e\n Se você conhece a semântica dos dados em jogo, então você conhece o comportamento\n\n\n do código. Se você conhece o comportamento do código, então conhece o custo do código.\n\n\n Uma vez que sei o custo, estou fazendo engenharia.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Dado este tipo e conjunto de métodos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype data struct {\n name string\n age int\n}\n\nfunc (d data) displayName() {\n fmt.Println(\u0026#34;My Name Is\u0026#34;, d.name)\n}\n\nfunc (d *data) setAge(age int) {\n d.age = age\n fmt.Println(d.name, \u0026#34;Is Age\u0026#34;, d.age)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode escrever o seguinte código.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n d := data{\n name: \u0026#34;Bill\u0026#34;,\n }\n\n f1 := d.displayName\n f1()\n d.name = \u0026#34;Joan\u0026#34;\n f1()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eMy Name Is Bill\nMy Name Is Bill\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você começa construindo um valor do tipo Data atribuindo-o à variável d.\n\n\n Então você pega o método displayName, vinculado a d, e atribui ele a uma variável\n\n\n chamada f1. Isso não é uma chamada de método, mas uma atribuição que cria um nível\n\n\n de indireção. Funções são valores em Go e pertencem ao conjunto de tipos internos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Após a atribuição, você pode chamar o método indiretamente através do uso da\n\n\n variável f1. Isso exibe o nome Bill. Então você altera os dados para que o nome\n\n\n agora seja Joan, e chama o método mais uma vez através da variável f1. Você não\n\n\n vê a mudança. Bill é o resultado mais uma vez. Então por que?\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/m1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/m1.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Isso tem a ver com a semântica que está em jogo. O método displayName está usando\n\n\n um receiver de valor então a semântica de valor está em jogo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (d data) displayName() {\n fmt.Println(\u0026#34;My Name Is\u0026#34;, d.name)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Isso significa que a variável f1 mantém e opera sua própria cópia de d.\n\n\n Então chamar o método através da variável f1, sempre usará a cópia e essa cópia\n\n\n é protegida contra alterações. Isso é o que você deseja com a semântica de valor.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora você vai fazer a mesma coisa, mas com o método setAge.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n d := data{\n name: \u0026#34;Bill\u0026#34;,\n }\n\n f2 := d.setAge\n f2(45)\n d.name = \u0026#34;Sammy\u0026#34;\n f2(45)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eBill Is Age 45\nSammy Is Age 45\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Desta vez o método setAge é atribuído à variável f2. Mais uma vez, o método\n\n\n é executado indiretamente através da variável f2 passando 45 para a idade de Bill.\n\n\n Então o nome de Bill é alterado para Sammy e a variável f2 é usada novamente para\n\n\n fazer a chamada. Desta vez você vê que o nome mudou.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/m2.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/m2.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n A função setAge está usando um receiver de ponteiro então setAge não opera na\n\n\n sua própria cópia da variável d, mas está operando diretamente na variável d.\n\n\n Portanto, f2 está operando com acesso compartilhado e você vê a mudança.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc (d *data) setAge(age int) {\n d.age = age\n fmt.Println(d.name, \u0026#34;Is Age\u0026#34;, d.age)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Sem conhecer a semântica dos dados em jogo, você não saberá o comportamento do código.\n\n\n Essa semântica de dados é real e afeta o comportamento.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eMétodos são funções que declaram uma variável receiver.\u003c/li\u003e\n \n \u003cli\u003eReceivers vinculam um método a um tipo e podem usar semântica de valor ou ponteiro.\u003c/li\u003e\n \n \u003cli\u003eSemântica de valor significa que uma cópia do valor é passada através dos limites do programa.\u003c/li\u003e\n \n \u003cli\u003eSemântica de ponteiro significa que uma cópia do endereço dos valores é passada através dos limites do programa.\u003c/li\u003e\n \n \u003cli\u003eAtenha-se a uma única semântica para um determinado tipo e seja consistente.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eCitações\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u0026#34;Métodos são válidos quando é prático e razoável que um dado exponha uma capacidade.\u0026#34; - William Kennedy\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/doc/effective_go.html#methods\" target=\"_blank\"\u003eMethods\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/05/methods-interfaces-and-embedded-types.html\" target=\"_blank\"\u003eMethods, Interfaces and Embedded Types in Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2018/01/escape-analysis-flaws.html\" target=\"_blank\"\u003eEscape-Analysis Flaws\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare methods and how the Go\n// compiler supports them.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n// user defines a user in the program.\ntype user struct {\n\tname string\n\temail string\n}\n\n// notify implements a method with a value receiver.\nfunc (u user) notify() {\n\tfmt.Printf(\"Sending User Email To %s\u003c%s\u003e\\n\",\n\t\tu.name,\n\t\tu.email)\n}\n\n// changeEmail implements a method with a pointer receiver.\nfunc (u *user) changeEmail(email string) {\n\tu.email = email\n}\n\nfunc main() {\n\n\t// Values of type user can be used to call methods\n\t// declared with both value and pointer receivers.\n\tbill := user{\"Bill\", \"bill@email.com\"}\n\tbill.changeEmail(\"bill@hotmail.com\")\n\tbill.notify()\n\n\t// Pointers of type user can also be used to call methods\n\t// declared with both value and pointer receiver.\n\tjoan := \u0026user{\"Joan\", \"joan@email.com\"}\n\tjoan.changeEmail(\"joan@hotmail.com\")\n\tjoan.notify()\n\n\t// Create a slice of user values with two users.\n\tusers := []user{\n\t\t{\"ed\", \"ed@email.com\"},\n\t\t{\"erick\", \"erick@email.com\"},\n\t}\n\n\t// Iterate over the slice of users switching\n\t// semantics. Not Good!\n\tfor _, u := range users {\n\t\tu.changeEmail(\"it@wontmatter.com\")\n\t}\n\n\t// Exception example: Using pointer semantics\n\t// for a collection of strings.\n\tkeys := make([]string, 10)\n\tfor i := range keys {\n\t\tkeys[i] = func() string { return \"key-gen\" }()\n\t}\n}\n","Hash":"au4D4R/VnVKngght4Rc2XGdemGk="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare methods against\n// a named type.\npackage main\n\nimport \"fmt\"\n\n// duration is a named type that represents a duration\n// of time in Nanosecond.\ntype duration int64\n\nconst (\n\tnanosecond duration = 1\n\tmicrosecond = 1000 * nanosecond\n\tmillisecond = 1000 * microsecond\n\tsecond = 1000 * millisecond\n\tminute = 60 * second\n\thour = 60 * minute\n)\n\n// setHours sets the specified number of hours.\nfunc (d *duration) setHours(h float64) {\n\t*d = duration(h * float64(hour))\n}\n\n// hours returns the duration as a floating point number of hours.\nfunc (d duration) hours() float64 {\n\thours := d / hour\n\tnsec := d % hour\n\treturn float64(hours) + (float64(nsec) * (1e-9 / 60 / 60))\n}\n\nfunc main() {\n\n\t// Declare a variable of type duration set to\n\t// its zero value.\n\tvar dur duration\n\n\t// Change the value of dur to equal\n\t// five hours.\n\tdur.setHours(5)\n\n\t// Display the new value of dur.\n\tfmt.Println(\"Hours:\", dur.hours())\n}\n","Hash":"IuJ8bHnDCKypUewaCwZkX03nm90="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare function variables.\npackage main\n\nimport \"fmt\"\n\n// data is a struct to bind methods to.\ntype data struct {\n\tname string\n\tage int\n}\n\n// displayName provides a pretty print view of the name.\nfunc (d data) displayName() {\n\tfmt.Println(\"My Name Is\", d.name)\n}\n\n// setAge sets the age and displays the value.\nfunc (d *data) setAge(age int) {\n\td.age = age\n\tfmt.Println(d.name, \"Is Age\", d.age)\n}\n\nfunc main() {\n\n\t// Declare a variable of type data.\n\td := data{\n\t\tname: \"Bill\",\n\t}\n\n\tfmt.Println(\"Proper Calls to Methods:\")\n\n\t// How we actually call methods in Go.\n\td.displayName()\n\td.setAge(45)\n\n\tfmt.Println(\"\\nWhat the Compiler is Doing:\")\n\n\t// This is what Go is doing underneath.\n\tdata.displayName(d)\n\t(*data).setAge(\u0026d, 45)\n\n\t// =========================================================================\n\n\tfmt.Println(\"\\nCall Value Receiver Methods with Variable:\")\n\n\t// Declare a function variable for the method bound to the d variable.\n\t// The function variable will get its own copy of d because the method\n\t// is using a value receiver.\n\tf1 := d.displayName\n\n\t// Call the method via the variable.\n\tf1()\n\n\t// Change the value of d.\n\td.name = \"Joan\"\n\n\t// Call the method via the variable. We don't see the change.\n\tf1()\n\n\t// =========================================================================\n\n\tfmt.Println(\"\\nCall Pointer Receiver Method with Variable:\")\n\n\t// Declare a function variable for the method bound to the d variable.\n\t// The function variable will get the address of d because the method\n\t// is using a pointer receiver.\n\tf2 := d.setAge\n\n\t// Call the method via the variable.\n\tf2(45)\n\n\t// Change the value of d.\n\td.name = \"Sammy\"\n\n\t// Call the method via the variable. We see the change.\n\tf2(45)\n}\n","Hash":"PrZm/jf6ZqVoeKrtnhqP4nt8HyI="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare and use function types.\npackage main\n\nimport \"fmt\"\n\n// event displays global events.\nfunc event(message string) {\n\tfmt.Println(message)\n}\n\n// data is a struct to bind methods to.\ntype data struct {\n\tname string\n\tage int\n}\n\n// event displays events for this data.\nfunc (d *data) event(message string) {\n\tfmt.Println(d.name, message)\n}\n\n// =============================================================================\n\n// fireEvent1 uses an anonymous function type.\nfunc fireEvent1(f func(string)) {\n\tf(\"anonymous\")\n}\n\n// handler represents a function for handling events.\ntype handler func(string)\n\n// fireEvent2 uses a function type.\nfunc fireEvent2(h handler) {\n\th(\"handler\")\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Declare a variable of type data.\n\td := data{\n\t\tname: \"Bill\",\n\t}\n\n\t// Use the fireEvent1 handler that accepts any\n\t// function or method with the right signature.\n\tfireEvent1(event)\n\tfireEvent1(d.event)\n\n\t// Use the fireEvent2 handler that accepts any\n\t// function or method of type `handler` or any\n\t// literal function or method with the right signature.\n\tfireEvent2(event)\n\tfireEvent2(d.event)\n\n\t// Declare a variable of type handler for the\n\t// global and method based event functions.\n\th1 := handler(event)\n\th2 := handler(d.event)\n\n\t// User the fireEvent2 handler that accepts\n\t// values of type handler.\n\tfireEvent2(h1)\n\tfireEvent2(h2)\n\n\t// User the fireEvent1 handler that accepts\n\t// any function or method with the right signature.\n\tfireEvent1(h1)\n\tfireEvent1(h2)\n}\n","Hash":"YNXA230N71kkz6RIa1V1aJf5pVM="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\nimport (\n\t\"sync/atomic\"\n\t\"syscall\"\n)\n\n// Sample code to show how it is important to use value or pointer semantics\n// in a consistent way. Choose the semantic that is reasonable and practical\n// for the given type and be consistent. One exception is an unmarshal\n// operation since that always requires the address of a value.\n\n// *****************************************************************************\n\n// These is a named type from the net package called IP and IPMask with a base\n// type that is a slice of bytes. Since we use value semantics for reference\n// types, the implementation is using value semantics for both.\n\ntype IP []byte\ntype IPMask []byte\n\n// Mask is using a value receiver and returning a value of type IP. This\n// method is using value semantics for type IP.\n\nfunc (ip IP) Mask(mask IPMask) IP {\n\tif len(mask) == IPv6len \u0026\u0026 len(ip) == IPv4len \u0026\u0026 allFF(mask[:12]) {\n\t\tmask = mask[12:]\n\t}\n\tif len(mask) == IPv4len \u0026\u0026 len(ip) == IPv6len \u0026\u0026 bytesEqual(ip[:12], v4InV6Prefix) {\n\t\tip = ip[12:]\n\t}\n\tn := len(ip)\n\tif n != len(mask) {\n\t\treturn nil\n\t}\n\tout := make(IP, n)\n\tfor i := 0; i \u003c n; i++ {\n\t\tout[i] = ip[i] \u0026 mask[i]\n\t}\n\treturn out\n}\n\n// ipEmptyString accepts a value of type IP and returns a value of type string.\n// The function is using value semantics for type IP.\n\nfunc ipEmptyString(ip IP) string {\n\tif len(ip) == 0 {\n\t\treturn \"\"\n\t}\n\treturn ip.String()\n}\n\n// *****************************************************************************\n\n// Should time use value or pointer semantics? If you need to modify a time\n// value should you mutate the value or create a new one?\n\ntype Time struct {\n\tsec int64\n\tnsec int32\n\tloc *Location\n}\n\n// Factory functions dictate the semantics that will be used. The Now function\n// returns a value of type Time. This means we should be using value\n// semantics and copy Time values.\n\nfunc Now() Time {\n\tsec, nsec := now()\n\treturn Time{sec + unixToInternal, nsec, Local}\n}\n\n// Add is using a value receiver and returning a value of type Time. This\n// method is using value semantics for Time.\n\nfunc (t Time) Add(d Duration) Time {\n\tt.sec += int64(d / 1e9)\n\tnsec := int32(t.nsec) + int32(d%1e9)\n\tif nsec \u003e= 1e9 {\n\t\tt.sec++\n\t\tnsec -= 1e9\n\t} else if nsec \u003c 0 {\n\t\tt.sec--\n\t\tnsec += 1e9\n\t}\n\tt.nsec = nsec\n\treturn t\n}\n\n// div accepts a value of type Time and returns values of built-in types.\n// The function is using value semantics for type Time.\n\nfunc div(t Time, d Duration) (qmod2 int, r Duration) {\n\t// Code here\n}\n\n// The only use pointer semantics for the `Time` api are these\n// unmarshal related functions.\n\nfunc (t *Time) UnmarshalBinary(data []byte) error {\nfunc (t *Time) GobDecode(data []byte) error {\nfunc (t *Time) UnmarshalJSON(data []byte) error {\nfunc (t *Time) UnmarshalText(data []byte) error {\n\n// *****************************************************************************\n\n// Factory functions dictate the semantics that will be used. The Open function\n// returns a pointer of type File. This means we should be using pointer\n// semantics and share File values.\n\nfunc Open(name string) (file *File, err error) {\n\treturn OpenFile(name, O_RDONLY, 0)\n}\n\n// Chdir is using a pointer receiver. This method is using pointer\n// semantics for File.\n\nfunc (f *File) Chdir() error {\n\tif f == nil {\n\t\treturn ErrInvalid\n\t}\n\tif e := syscall.Fchdir(f.fd); e != nil {\n\t\treturn \u0026PathError{\"chdir\", f.name, e}\n\t}\n\treturn nil\n}\n\n// epipecheck accepts a pointer of type File.\n// The function is using pointer semantics for type File.\n\nfunc epipecheck(file *File, e error) {\n\tif e == syscall.EPIPE {\n\t\tif atomic.AddInt32(\u0026file.nepipe, 1) \u003e= 10 {\n\t\t\tsigpipe()\n\t\t}\n\t} else {\n\t\tatomic.StoreInt32(\u0026file.nepipe, 0)\n\t}\n}\n","Hash":"FK/bO7t9FZJg21E4iopcF1AuQx0="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo como ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declare uma struct que representa um jogador de baseball. Inclua name, atBats e hits.\n\n\n Declare um método que calcula a média de rebatidas de um jogador. A fórmula é Hits / AtBats.\n\n\n Declare uma slice desse tipo e inicialize a slice com vários jogadores. Itere a slice\n\n\n mostrando o nome dos jogadores e a média de rebatidas.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct that represents a baseball player. Include name, atBats and hits.\n// Declare a method that calculates a player's batting average. The formula is hits / atBats.\n// Declare a slice of this type and initialize the slice with several players. Iterate over\n// the slice displaying the players name and batting average.\npackage main\n\n// Add imports.\n\n// Declare a struct that represents a ball player.\n// Include fields called name, atBats and hits.\n\n// Declare a method that calculates the batting average for a player.\nfunc ( /* receiver */ ) average() /* return type */ {\n}\n\nfunc main() {\n\n\t// Create a slice of players and populate each player\n\t// with field values.\n\n\t// Display the batting average for each player in the slice.\n}\n","Hash":"34Nejt1R9Zc535gAjJpmtw/nR2U="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare a struct that represents a baseball player. Include name, atBats and hits.\n// Declare a method that calculates a players batting average. The formula is hits / atBats.\n// Declare a slice of this type and initialize the slice with several players. Iterate over\n// the slice displaying the players name and batting average.\npackage main\n\nimport \"fmt\"\n\n// player represents a person in the game.\ntype player struct {\n\tname string\n\tatBats int\n\thits int\n}\n\n// average calculates the batting average for a player.\nfunc (p *player) average() float64 {\n\tif p.atBats == 0 {\n\t\treturn 0.0\n\t}\n\n\treturn float64(p.hits) / float64(p.atBats)\n}\n\nfunc main() {\n\n\t// Create a few players.\n\tps := []player{\n\t\t{\"bill\", 10, 7},\n\t\t{\"jim\", 12, 6},\n\t\t{\"ed\", 6, 4},\n\t}\n\n\t// Display the batting average for each player.\n\tfor i := range ps {\n\t\tfmt.Printf(\"%s: AVG[.%.f]\\n\", ps[i].name, ps[i].average()*1000)\n\t}\n\n\t// Why did I not choose this form?\n\tfor _, p := range ps {\n\t\tfmt.Printf(\"%s: AVG[.%.f]\\n\", p.name, p.average()*1000)\n\t}\n}\n","Hash":"N9Xz00m121bwbSJT+35/3f86GAM="}]}]} ,"composition-assertions":{"Title":"Conversões e Asserções de Tipos","Description":"Aprenda como conversões e asserções de tipos funcionam.","Pages":[{"Title":"Conversões e Asserções de Tipos","Content":"\n \u003ch2\u003eConversões e Asserções de Tipos\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira? Utilize o Nosso\u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Uma conversão de tipo permite que os dados de um tipo se convertam para outro tipo. \n\n\n Uma asserção de tipo permite que você faça a pergunta se há um valor do tipo dado armazenado dentro de uma interface.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Conversões de Interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Asserções de Tipo em Tempo de Execução\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Mudanças de Comportamento\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eConversões Implícitas de Interface\u003c/h2\u003e\n \n \n \u003cp\u003e\n Como você viu no último exemplo, um valor de interface de um tipo pode ser passado para um\n\n\n diferente tipo de interface se o valor concreto armazenado dentro da interface implementar\n\n\n ambos os comportamentos. Isso poderia ser considerado uma conversão implícita de interface, mas é\n\n\n melhor pensar em como os dados concretos estão sendo movidos por meio de interfaces em um\n\n\n estado desacoplado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Mover interface {\n Move()\n}\n\ntype Locker interface {\n Lock()\n Unlock()\n}\n\ntype MoveLocker interface {\n Mover\n Locker\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Dadas essas três interfaces, onde MoveLocker é a composição de Mover e Locker.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype bike struct{}\n\nfunc (bike) Move() {\n fmt.Println(\u0026#34;Moving the bike\u0026#34;)\n}\n\nfunc (bike) Lock() {\n fmt.Println(\u0026#34;Locking the bike\u0026#34;)\n}\n\nfunc (bike) Unlock() {\n fmt.Println(\u0026#34;Unlocking the bike\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n E dado esse tipo concreto \u0026#34;bike\u0026#34; que implementa todas as três interfaces. O que você pode fazer?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar ml MoveLocker\nvar m Mover\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode construir um valor do tipo MoveLocker e Mover para seu estado de valor zero.\n\n\n Esses são valores de interface que são verdadeiramente sem valor.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eml = bike{}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Então, você pode construir um valor do tipo \u0026#34;bike\u0026#34; para seu estado de valor zero e atribuir uma cópia à variável MoveLocker \u0026#34;ml\u0026#34;. \n\n\n Isso é possível porque uma \u0026#34;bike\u0026#34; implementa todos os três comportamentos, e o compilador vê que a implementação existe.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003em = ml\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode então atribuir a variável MoveLocker \u0026#34;ml\u0026#34; à variável Mover \u0026#34;m\u0026#34;. \n\n\n Isso é possível porque não estou atribuindo o valor de interface \u0026#34;ml\u0026#34;, mas o valor concreto armazenado dentro de \u0026#34;ml\u0026#34;, que é um valor de \u0026#34;bike\u0026#34;. \n\n\n O compilador sabe que qualquer valor concreto armazenado dentro de \u0026#34;ml\u0026#34; também deve implementar a interface \u0026#34;Mover\u0026#34;.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n No entanto, essa atribuição não é válida.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eml = m\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Saída:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ecannot use m (type Mover) as type MoveLocker in assignment:\n Mover does not implement MoveLocker (missing Lock method)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você não pode atribuir a variável Mover \u0026#34;m\u0026#34; de volta à variável MoverLocker \u0026#34;ml\u0026#34; porque o compilador só pode garantir que o valor \n\n\n concreto armazenado dentro de \u0026#34;m\u0026#34; sabe como realizar a ação Move. \n\n\n Ele não sabe em tempo de compilação se o valor concreto também sabe como realizar as ações Lock e Unlock.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eMecânicas de Asserção de Tipo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Uma asserção de tipo permite que você, em tempo de execução, faça uma pergunta: há um valor do tipo dado armazenado dentro de uma interface. \n\n\n Isso é feito usando a sintaxe m.(bike).\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eb := m.(bike)\nml = b\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste caso, você está perguntando se há um valor do tipo \u0026#34;bike\u0026#34; armazenado dentro de \u0026#34;m\u0026#34; no momento em que o código é executado. \n\n\n Se houver, então a variável \u0026#34;b\u0026#34; recebe uma cópia do valor \u0026#34;bike\u0026#34; armazenado. \n\n\n Em seguida, a cópia pode ser armazenada dentro da variável de interface \u0026#34;ml\u0026#34;.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se não houver um valor do tipo \u0026#34;bike\u0026#34; armazenado dentro do valor de interface, o programa entra em pânico. \n\n\n Isso é útil quando deve absolutamente haver um valor do tipo \u0026#34;bike\u0026#34; armazenado. \n\n\n No entanto, se houver uma chance de que não haja um valor do tipo \u0026#34;bike\u0026#34; e isso seja válido, então você precisa da segunda forma da asserção de tipo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eb, ok := m.(bike)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Nesta forma, se \u0026#34;ok\u0026#34; for verdadeiro, há um valor do tipo \u0026#34;bike\u0026#34; armazenado dentro da interface. \n\n\n Se \u0026#34;ok\u0026#34; for falso, então não há um valor do tipo \u0026#34;bike\u0026#34; e o programa não entra no modo pânico. \n\n\n No entanto, a variável \u0026#34;b\u0026#34; ainda é do tipo \u0026#34;bike\u0026#34;, mas é definida para seu estado de valor zero.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n mvs := []fmt.Stringer{\n Car{},\n Cloud{},\n }\n\n for i := 0; i \u0026lt; 10; i\u0026#43;\u0026#43; {\n rn := rand.Intn(2)\n\n if v, is := mvs[rn].(Cloud); is {\n fmt.Println(\u0026#34;Got Lucky:\u0026#34;, v)\n continue\n }\n\n fmt.Println(\u0026#34;Got Unlucky\u0026#34;)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Supondo que o programa declare dois tipos denominados Car (Carro) e Cloud (Nuvem) \n\n\n que implementem a interface fmt.Stringer, você pode construir uma coleção que permite \n\n\n armazenar um valor tanto de Carro quanto de Nuvem. Então, 10 vezes, você escolhe aleatoriamente \n\n\n um número de 0 a 1 e realiza uma asserção de tipo para ver se o valor naquele índice aleatório contém um valor de Nuvem. \n\n\n Como é possível que não seja do tipo Nuvem, a segunda forma da asserção de tipo é crucial aqui.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating when implicit interface conversions\n// are provided by the compiler.\npackage main\n\nimport \"fmt\"\n\n// Mover provides support for moving things.\ntype Mover interface {\n\tMove()\n}\n\n// Locker provides support for locking and unlocking things.\ntype Locker interface {\n\tLock()\n\tUnlock()\n}\n\n// MoveLocker provides support for moving and locking things.\ntype MoveLocker interface {\n\tMover\n\tLocker\n}\n\n// bike represents a concrete type for the example.\ntype bike struct{}\n\n// Move can change the position of a bike.\nfunc (bike) Move() {\n\tfmt.Println(\"Moving the bike\")\n}\n\n// Lock prevents a bike from moving.\nfunc (bike) Lock() {\n\tfmt.Println(\"Locking the bike\")\n}\n\n// Unlock allows a bike to be moved.\nfunc (bike) Unlock() {\n\tfmt.Println(\"Unlocking the bike\")\n}\n\nfunc main() {\n\n\t// Declare variables of the MoveLocker and Mover interfaces set to their\n\t// zero value.\n\tvar ml MoveLocker\n\tvar m Mover\n\n\t// Create a value of type bike and assign the value to the MoveLocker\n\t// interface value.\n\tml = bike{}\n\n\t// An interface value of type MoveLocker can be implicitly converted into\n\t// a value of type Mover. They both declare a method named move.\n\tm = ml\n\n\t// prog.go:68: cannot use m (type Mover) as type MoveLocker in assignment:\n\t//\t Mover does not implement MoveLocker (missing Lock method)\n\tml = m\n\n\t// Interface type Mover does not declare methods named lock and unlock.\n\t// Therefore, the compiler can't perform an implicit conversion to assign\n\t// a value of interface type Mover to an interface value of type MoveLocker.\n\t// It is irrelevant that the concrete type value of type bike that is stored\n\t// inside of the Mover interface value implements the MoveLocker interface.\n\n\t// We can perform a type assertion at runtime to support the assignment.\n\n\t// Perform a type assertion against the Mover interface value to access\n\t// a COPY of the concrete type value of type bike that was stored inside\n\t// of it. Then assign the COPY of the concrete type to the MoveLocker\n\t// interface.\n\tb := m.(bike)\n\tml = b\n\n\t// It's important to note that the type assertion syntax provides a way\n\t// to state what type of value is stored inside the interface. This is\n\t// more powerful from a language and readability standpoint, than using\n\t// a casting syntax, like in other languages.\n}\n","Hash":"2WQGiMEGXUUlVP4K9qheLDu0nQc="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating that type assertions are a runtime and\n// not compile time construct.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\n// car represents something you drive.\ntype car struct{}\n\n// String implements the fmt.Stringer interface.\nfunc (car) String() string {\n\treturn \"Vroom!\"\n}\n\n// cloud represents somewhere you store information.\ntype cloud struct{}\n\n// String implements the fmt.Stringer interface.\nfunc (cloud) String() string {\n\treturn \"Big Data!\"\n}\n\nfunc main() {\n\n\t// Create a slice of the Stringer interface values.\n\tmvs := []fmt.Stringer{\n\t\tcar{},\n\t\tcloud{},\n\t}\n\n\t// Let's run this experiment ten times.\n\tfor i := 0; i \u003c 10; i++ {\n\n\t\t// Choose a random number from 0 to 1.\n\t\trn := rand.Intn(2)\n\n\t\t// Perform a type assertion that we have a concrete type\n\t\t// of cloud in the interface value we randomly chose.\n\t\tif v, is := mvs[rn].(cloud); is {\n\t\t\tfmt.Println(\"Got Lucky:\", v)\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Println(\"Got Unlucky\")\n\t}\n}\n","Hash":"ue/tsEsz3OfGbss7yERoYMKFcqY="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how method sets can affect behavior.\npackage main\n\nimport \"fmt\"\n\n// user defines a user in the system.\ntype user struct {\n\tname string\n\temail string\n}\n\n// String implements the fmt.Stringer interface.\nfunc (u *user) String() string {\n\treturn fmt.Sprintf(\"My name is %q and my email is %q\", u.name, u.email)\n}\n\nfunc main() {\n\n\t// Create a value of type user.\n\tu := user{\n\t\tname: \"Bill\",\n\t\temail: \"bill@ardanlabs.com\",\n\t}\n\n\t// Display the values.\n\tfmt.Println(u)\n\tfmt.Println(\u0026u)\n}\n","Hash":"6KF4CjCIcjL2H4fc39Bav/ow2l8="}]}]} ,"generics-basics":{"Title":"Básicos","Description":"Aprenda como escrever uma função genérica básica de print.","Pages":[{"Title":"Genéricos - Básicos","Content":"\n \u003ch2\u003eGenéricos - Básicos\u003c/h2\u003e\n \n \n \u003cp\u003e\n Aprenda como escrever uma função genérica básica de print.\n \u003c/p\u003e\n \n\n \u003ch2\u003eVideo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Assista à palestra que dei sobre Genéricos, que apresenta todos os\n\n\n exemplos desta seção do Tour.\n \u003c/p\u003e\n \n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gIEPspmbMHM\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Implementação concreta do print\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2\u003c/b\u003e: Implementação de asserção de tipo para o print\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3\u003c/b\u003e: Implementação de reflexão para print\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4\u003c/b\u003e: Implementação genérica de print\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eExplicação\u003c/h2\u003e\n \n \n \u003cp\u003e\n Se você deseja escrever uma única função de impressão que possa exibir uma slice \n\n\n de qualquer tipo dado e não usar reflexão, você pode usar a nova sintaxe de genéricos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc print[T any](slice []T) {\n fmt.Print(\u0026#34;Generic: \u0026#34;)\n \n for _, v := range slice {\n fmt.Print(v, \u0026#34; \u0026#34;)\n }\n\n fmt.Print(\u0026#34;\\n\u0026#34;)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta é uma implementação de uma única função de impressão que pode exibir uma slice de qualquer tipo \n\n\n dado usando a nova sintaxe de genéricos. O que é bom nesta sintaxe é que o código dentro da função pode usar a sintaxe e \n\n\n funções integradas que funcionariam com um tipo concreto. Isso não é o caso quando você usa a interface vazia \n\n\n para escrever código genérico.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Deve haver uma maneira de dizer ao compilador que você não irá declarar o tipo T explicitamente, \n\n\n mas ele deve ser determinado pelo compilador durante a compilação. \n\n\n A nova sintaxe usa colchetes para isso. Os colchetes definem uma lista de identificadores \n\n\n de tipo genéricos que representam tipos específicos para a função que precisam ser determinados durante a compilação. \n\n\n É assim que você diz ao compilador que os tipos com esses nomes não serão declarados antes que o programa seja compilado. \n\n\n Esses tipos precisam ser resolvidos durante a compilação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Nota: Você pode ter vários identificadores de tipo definidos dentro dos colchetes, \n\n\n embora o exemplo atual esteja usando apenas um. Ex. [T, S, R any]\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você pode nomear esses identificadores de tipo como quiser para ajudar na legibilidade do código. \n\n\n Neste caso, o código está usando a letra maiúscula T para descrever que uma slice de algum tipo T (a ser determinado durante a compilação) será passada. \n\n\n É um padrão usar letras maiúsculas únicas quando se trata de coleções e também é uma convenção que remonta a linguagens de programação mais antigas, \n\n\n como C++ e Java.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Há também o uso da palavra \u0026#34;any\u0026#34; dentro dos colchetes. Isso representa uma restrição sobre o que o tipo T pode ser. \n\n\n O compilador requer que todos os tipos genéricos tenham uma restrição bem definida. \n\n\n A restrição \u0026#34;any\u0026#34; é pré-declarada pelo compilador e afirma que não há restrições quanto ao que o tipo T pode ser.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003enumbers := []int{1, 2, 3}\nprint[int](numbers)\n\nstrings := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;}\nprint[string](strings)\n\nfloats := []float64{1.7, 2.2, 3.14}\nprint[float64](floats)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta é a maneira de fazer chamadas para a função de print genérica, onde as informações de tipo para T são fornecidas explicitamente no local da chamada. \n\n\n A sintaxe emula a ideia de que a declaração da função \u0026#39;func name[T any](slice []T)\u0026#39; define dois conjuntos de parâmetros. O primeiro conjunto é o tipo que se mapeia \n\n\n para os identificadores de tipo correspondentes e o segundo é o dado que se mapeia para as variáveis de entrada correspondentes.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Felizmente, o compilador pode inferir o tipo e eliminar a necessidade de passar explicitamente \n\n\n as informações de tipo no local da chamada.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003enumbers := []int{1, 2, 3}\nprint(numbers)\n\nstrings := []string{\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;}\nprint(strings)\n\nfloats := []float64{1.7, 2.2, 3.14}\nprint(floats)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este código mostra como você pode chamar as funções genéricas de print sem a necessidade de passar as informações de tipo explicitamente. \n\n\n No local da chamada da função, o compilador consegue identificar o tipo a ser usado para T e construir uma versão concreta da função para suportar slices desse tipo.\n\n\n O compilador tem a capacidade de inferir o tipo com base nas informações que possui no local da chamada a partir dos dados que estão sendo passados.\n \u003c/p\u003e\n \n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how concrete implementations of print functions that can\n// only work with slices of the specified type.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc printNumbers(numbers []int) {\n\tfmt.Print(\"Numbers: \")\n\n\tfor _, num := range numbers {\n\t\tfmt.Print(num, \" \")\n\t}\n\n\tfmt.Print(\"\\n\")\n}\n\nfunc printStrings(strings []string) {\n\tfmt.Print(\"Strings: \")\n\n\tfor _, str := range strings {\n\t\tfmt.Print(str, \" \")\n\t}\n\n\tfmt.Print(\"\\n\")\n}\n\nfunc main() {\n\tnumbers := []int{1, 2, 3}\n\tprintNumbers(numbers)\n\n\tstrings := []string{\"A\", \"B\", \"C\"}\n\tprintStrings(strings)\n}\n","Hash":"nHivjUU5W1B5z8jFm1TFVOhUE6E="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to write a function that provides an empty interface\n// solution which uses type assertions for the different concrete slices to be\n// supported. We've basically moved the functions from above into case statements.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc printAssert(v interface{}) {\n\tfmt.Print(\"Assert: \")\n\n\tswitch list := v.(type) {\n\tcase []int:\n\t\tfor _, num := range list {\n\t\t\tfmt.Print(num, \" \")\n\t\t}\n\n\tcase []string:\n\t\tfor _, str := range list {\n\t\t\tfmt.Print(str, \" \")\n\t\t}\n\t}\n\n\tfmt.Print(\"\\n\")\n}\n\nfunc main() {\n\tnumbers := []int{1, 2, 3}\n\tprintAssert(numbers)\n\n\tstrings := []string{\"A\", \"B\", \"C\"}\n\tprintAssert(strings)\n}\n","Hash":"KfiX29hKp8DnzlZSWGm7WEwlIQA="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to write a function that provides a reflection\n// solution which allows a slice of any type to be provided and printed. This\n// is a generic function thanks to the reflect package.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\nfunc printReflect(v interface{}) {\n\tfmt.Print(\"Reflect: \")\n\n\tval := reflect.ValueOf(v)\n\tif val.Kind() != reflect.Slice {\n\t\treturn\n\t}\n\n\tfor i := 0; i \u003c val.Len(); i++ {\n\t\tfmt.Print(val.Index(i).Interface(), \" \")\n\t}\n\n\tfmt.Print(\"\\n\")\n}\n\nfunc main() {\n\tnumbers := []int{1, 2, 3}\n\tprintReflect(numbers)\n\tprint(numbers)\n\n\tstrings := []string{\"A\", \"B\", \"C\"}\n\tprintReflect(strings)\n}\n","Hash":"cxzabIpoqtllWWxtgTre3edzuR4="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to write a function that provides a generics\n// solution which allows a slice of any type T (to be determined later) to be\n// passed and printed.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n// To avoid the ambiguity with array declarations, type parameters require a\n// constraint to be applied. The `any` constraint states there is no constraint\n// on what type T can become. The predeclared identifier `any` is an alias for\n// `interface{}`.\n//\n// This code more closely resembles the concrete implementations that we started\n// with and is easier to read than the reflect implementation.\n\nfunc print[T any](slice []T) {\n\tfmt.Print(\"Generic: \")\n\n\tfor _, v := range slice {\n\t\tfmt.Print(v, \" \")\n\t}\n\n\tfmt.Print(\"\\n\")\n}\n\n// =============================================================================\n\nfunc main() {\n\tnumbers := []int{1, 2, 3}\n\tprint(numbers)\n\n\tstrings := []string{\"A\", \"B\", \"C\"}\n\tprint(strings)\n}\n","Hash":"+rhgLI9ZrEl06woMwIe1lhKWfjw="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Implemente uma função genérica chamada marshal que possa aceitar qualquer valor e\n\n\n transformar esse valor em JSON, retornando o JSON e um erro. Declare\n\n\n uma struct chamada \u0026#34;User\u0026#34; com dois campos, \u0026#34;Name\u0026#34; e \u0026#34;Age\u0026#34;. Em seguida, crie um\n\n\n valor do tipo \u0026#34;User\u0026#34; e passe o valor para a função genérica \u0026#34;marshal\u0026#34;.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic function that can marshal JSON.\npackage main\n\n// Add imports.\n\n// Implement the generic function named marshal that can accept any value\n// of type T and marshal that value into JSON.\n\n// Declare a struct type named User with two fields, Name and Age.\n\nfunc main() {\n\t// Construct a value of type User.\n\n\t// Call the generic marshal function.\n\n\t// Print the JSON produced by the marshal function.\n}\n","Hash":"9gD0O6iS29Jfj6gB+2ACNByyHdc="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Implement a generic function that can marshal JSON.\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// Implement the generic function named marshal that can accept any value\n// of type T and marshal that value into JSON.\nfunc marshal[T any](v T) ([]byte, error) {\n\tdata, err := json.Marshal(v)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\n// Declare a struct type named User with two fields, Name and Age.\ntype User struct {\n\tName string\n\tAge int\n}\n\nfunc main() {\n\n\t// Construct a value of type User.\n\tu := User{\n\t\tName: \"Bill\",\n\t\tAge: 10,\n\t}\n\n\t// Call the generic marshal function.\n\tdata, err := marshal(u)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\t// Print the JSON produced by the marshal function.\n\tfmt.Println(string(data))\n}\n","Hash":"RpSVxCKUMCrVM3yNqmj4J7bHnG0="}]}]} ,"interfaces":{"Title":"Interfaces","Description":"Interfaces estruturam e incentivam o design por composição em programas.","Pages":[{"Title":"Interfaces","Content":"\n \u003ch2\u003eInterfaces\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Interfaces estruturam e incentivam o design por composição em programas. Elas permitem\n\n\n e impõem divisões limpas entre componentes. A padronização das interfaces pode definir\n\n\n expectativas claras e consistentes. Desacoplar significa reduzir as dependências entre\n\n\n componentes e os tipos que eles usam. Isso leva à corretude, qualidade e facilidade de\n\n\n manutenção.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Código Repetitivo Que Precisa de Polimorfismo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Polimorfismo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Conjunto de Métodos\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Endereço do Valor\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Armazenamento Por Valor\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e Asserções de Tipo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e7:\u003c/b\u003e Asserções Condicionais de Tipo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e8:\u003c/b\u003e A Interface Vazia e Switches de Tipo\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e9:\u003c/b\u003e Armazenando Valores\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eSemântica de Interface\u003c/h2\u003e\n \n \n \u003cp\u003e\n Interfaces permitem agrupar dados concretos de acordo com o que os dados podem\n\n\n fazer. Trata-se de focar no que os dados podem fazer e não no que os dados são.\n\n\n As interfaces também ajudam meu código a se desacoplar de mudanças, solicitando\n\n\n dados concretos baseado no que eles podem fazer. Não é limitado a um tipo de dado.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você deve fazer o possível para entender quais alterações de dados estão por vir\n\n\n e usar interfaces para desacoplar o seu programa dessas alterações. Interfaces\n\n\n devem descrever comportamento e não estado. Elas devem ser verbos e não substantivos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Interfaces generalizadas que focam no comportamento são as melhores. Interfaces com\n\n\n mais de um método têm mais de um motivo para mudar. Interfaces baseadas em substantivos\n\n\n tendem a ser menos reutilizáveis, são mais suscetíveis a mudanças e anulam o propósito\n\n\n de uma interface. A incerteza sobre a mudança não é uma licença para adivinhar, mas\n\n\n uma diretiva para PARAR e aprender mais. Você deve distinguir entre código que defende\n\n\n contra fraudes vs que protege contra acidentes.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Use uma interface quando:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eOs usuários da API precisam fornecer detalhes de implementação.\u003c/li\u003e\n \n \u003cli\u003eAs APIs têm múltiplas implementações que precisam ser mantidas internamente.\u003c/li\u003e\n \n \u003cli\u003ePartes da API que podem mudar foram identificadas e requerem desacoplamento.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Não use uma interface:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eSó para usar uma interface.\u003c/li\u003e\n \n \u003cli\u003ePara generalizar um algoritmo.\u003c/li\u003e\n \n \u003cli\u003eQuando os usuários declaram suas próprias interfaces.\u003c/li\u003e\n \n \u003cli\u003eSe não estiver claro como a interface melhora o código.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eInterfaces não têm valor\u003c/h2\u003e\n \n \n \u003cp\u003e\n A primeira coisa importante a entender é que um tipo interface declara um tipo sem valor.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype reader interface {\n read(b []byte) (int, error)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O tipo reader não é um tipo struct, mas um tipo interface. A sua declaração não\n\n\n é baseada em estado, mas em comportamento. Tipos interface declaram um conjunto\n\n\n de métodos de comportamento que os dados concretos devem exibir para satisfazer\n\n\n a interface. Não há nada de concreto sobre os tipos interface, portanto eles não\n\n\n têm valor.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar r reader\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Por não possuírem valor, a construção de uma variável (como r) é estranha porque\n\n\n no nosso modelo de programação, r não existe, não tem valor. Não há nada no próprio\n\n\n r que você possa manipular ou transformar. Este é um conceito crítico de entender.\n\n\n Eu nunca trabalho com valores de interface, apenas com valores concretos. Uma\n\n\n interface tem uma representação do compilador (tipo interno), mas em nosso modelo\n\n\n de programação, interfaces não têm valor.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eImplementando Interfaces\u003c/h2\u003e\n \n \n \u003cp\u003e\n Go é uma linguagem que é sobre convenção acima de configuração. Quando se trata\n\n\n de um tipo concreto que implementa uma interface não é diferente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype reader interface {\n read(b []byte) (int, error)\n}\n\ntype file struct {\n name string\n}\n\nfunc (file) read(b []byte) (int, error) {\n s := \u0026#34;\u0026lt;rss\u0026gt;\u0026lt;channel\u0026gt;\u0026lt;title\u0026gt;Going Go\u0026lt;/title\u0026gt;\u0026lt;/channel\u0026gt;\u0026lt;/rss\u0026gt;\u0026#34;\n copy(b, s)\n return len(s), nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O código declara um tipo chamado file e então declara um método chamado read. Por\n\n\n causa dessas duas declarações, você pode dizer o seguinte:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;O tipo concreto file agora implementa a interface reader usando semântica de valor\u0026#34;\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Toda palavra dita é importante. Em Go, tudo o que você precisa fazer é declarar o\n\n\n conjunto completo de métodos de comportamento definidos por uma interface para\n\n\n implementar a interface. Neste caso, foi isso que eu fiz, uma vez que a interface\n\n\n reader declara apenas um único ato de comportamento chamado read.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype reader interface {\n read(b []byte) (int, error)\n}\n\ntype pipe struct {\n name string\n}\n\nfunc (pipe) read(b []byte) (int, error) {\n s := `{name: \u0026#34;Bill\u0026#34;, title: \u0026#34;developer\u0026#34;}`\n copy(b, s)\n return len(s), nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este código declara um tipo chamado pipe e então declara um método chamado read.\n\n\n Por causa dessas duas declarações, você pode dizer o seguinte:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;O tipo concreto piep agora implementa a interface reader usando semântica de valor\u0026#34;\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Agora você tem dois tipos concretos que implementam a interface reader. Dois tipos\n\n\n concretos, cada um com sua própria implementação. Um tipo está lendo arquivos do sistema\n\n\n e outros da rede.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003ePolimorfismo\u003c/h2\u003e\n \n \n \u003cp\u003e\n Polimorfismo significa que um pedaço do código muda seu comportamento dependendo do\n\n\n dado concreto no qual está operando. Isso foi dito por Tom Kurtz, que é o inventor de\n\n\n BASIC. Essa é a definição que usaremos daqui para frente.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// retrieve pode ler qualquer dispositivo e processar os dados.\nfunc retrieve(r reader) error {\n data := make([]byte, 100)\n\n len, err := r.read(data)\n if err != nil {\n return err\n }\n\n fmt.Println(string(data[:len]))\n return nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Dê uma olhada no tipo de dados que a função aceita. Ela quer um valor do tipo reader.\n\n\n Isso é impossível, pois reader é uma interface e interfaces não têm valor.\n\n\n Não se pode pedir por um valor reader, eles não existem.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Se a função não está pedindo por um valor reader, então pelo que a função está\n\n\n pedindo? Ela está pedindo a única coisa que pode pedir: dados concretos.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A função retrieve é uma função polimórfica porque solicita dados concretos não\n\n\n com base no que os dados são (tipo concreto), mas com base no que os dados podem\n\n\n fazer (tipo interface).\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ef := file{\u0026#34;data.json\u0026#34;}\np := pipe{\u0026#34;cfg_service\u0026#34;}\n\nretrieve(f)\nretrieve(p)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você pode construir dois valores concretos, um do tipo file e outro do tipo pipe.\n\n\n Então você pode passar uma cópia de cada valor para a função polimórfica. Isso ocorre\n\n\n porque cada um desses valores implementa o conjunto completo de métodos de comportamento\n\n\n definido pela interface reader.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando o valor concreto de file é passado para retrieve, o valor é armazenado dentro\n\n\n de um tipo interno de duas palavras que representa o valor da interface.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/i1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/i1.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n A segunda palavra do valor da interface aponta para o valor que está sendo armazenado.\n\n\n Nesse caso, é uma cópia do valor de file, já que a semântica de valor está em jogo. A\n\n\n primeira palavra aponta para uma estrutura de dados especial chamada iTable.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A iTable serve a 2 propósitos:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eDescreve o tipo do valor que está sendo armazenado. No meu caso, é um valor de file.\u003c/li\u003e\n \n \u003cli\u003eFornece ponteiros de função para a implementação concreta do conjunto de métodos do tipo de valor que está sendo armazenado.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Quando a chamada de read é feita no valor da interface, uma pesquisa na iTable é executada\n\n\n para encontrar a implementação concreta do método read associado ao tipo.\n\n\n Em seguida, a chamada do método é feita ao valor armazenado na segunda palavra.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você pode dizer que retrieve é uma função polimórfica porque o valor concreto de pipe\n\n\n pode ser passado para retrieve e agora a chamada para read feita para o valor da interface\n\n\n muda seu comportamento. Desta vez, a chamada para read está lendo uma rede em ved de ler\n\n\n um arquivo.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eRegras de Conjunto de Métodos\u003c/h2\u003e\n \n \n \u003cp\u003e\n A implementação de uma interface usando semântica de ponteiro aplica algumas\n\n\n restrições à conformidade da interface.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype notifier interface {\n notify()\n}\n\ntype user struct {\n name string\n email string\n}\n\nfunc (u *user) notify() {\n fmt.Printf(\u0026#34;Sending User Email To %s\u0026lt;%s\u0026gt;\\n\u0026#34;, u.name, u.email)\n}\n\nfunc sendNotification(n notifier) {\n n.notify()\n}\n\nfunc main() {\n u := user{\u0026#34;Bill\u0026#34;, \u0026#34;bill@email.com\u0026#34;}\n sendNotification(u)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A interface notifier é implementada pelo tipo user usando semântica de ponteiro.\n\n\n Quando a semântica de valor é usada para fazer uma chamada polimórfica, a seguinte\n\n\n mensagem do compilador é produzida.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e\u0026#34;cannot use u (type user) as type notifier in argument to sendNotification:\nuser does not implement notifier (notify method has pointer receiver)\u0026#34;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Isso ocorre porque existe um conjunto especial de regras na especificação sobre\n\n\n conjuntos de métodos. Essas regras definem quais métodos são anexados a valores\n\n\n e ponteiros de um tipo. Elas existem para manter o maior nível de integridade no\n\n\n meu programa.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Estas são as regras definidas na especificação:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003ePara qualquer valor do tipo T, apenas os métodos implementados com um receiver de valor para esse tipo pertencem ao conjunto de métodos desse valor.\u003c/li\u003e\n \n \u003cli\u003ePara qualquer endereço do tipo T, todos os métodos implementados para esse tipo pertencem ao conjunto de métodos desse valor.\n\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Em outras palavras, ao trabalhar com um endereço (ponteiro), todos os métodos implementados\n\n\n são anexados e disponíveis para serem chamados. Ao trabalhar com um valor, somente\n\n\n os métodos implementados com receiver de valor são anexados e disponíveis para\n\n\n serem chamados.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Na lição anterior sobre métodos, você foi capaz de chamar um método usando um\n\n\n dado concreto, independente da semântica dos dados declarados pelo receptor.\n\n\n Isso ocorre porque o compilador pode se ajustar para fazer a chamada. Neste caso,\n\n\n um valor está sendo armazenado dentro de uma interface e os métodos devem existir.\n\n\n Nenhum ajuste pode ser feito.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A questão agora é: Por que os métodos implementados com receivers de ponteiro\n\n\n não podem ser anexados a valores do tipo T? Qual é o problema de integridade aqui?\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Uma razão é porque você não pode garantir que todo valor do tipo T é endereçável.\n\n\n Se um valor não tiver um endereço, ele não poderá ser compartilhado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype duration int\n\nfunc (d *duration) notify() {\n fmt.Println(\u0026#34;Sending Notification in\u0026#34;, *d)\n}\n\nfunc main() {\n duration(42).notify()\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Erro de Compilação:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ecannot call pointer method on duration(42)\ncannot take the address of duration(42)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Neste exemplo, o valor de 42 é uma constante do kind int. Mesmo que o valor seja\n\n\n convertido para o tipo duration, ele não está sendo armazenado em uma variável.\n\n\n Isso significa que o valor nunca está na stack ou na heap. Não há um endereço. Constantes\n\n\n existem apenas em tempo de compilação.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A segunda razão é a razão maior. O compilador está informando que você não tem\n\n\n permissão para usar semântica de valor se tiver optado por usar semântica de ponteiro.\n\n\n Em outras palavras, você está sendo forçado a compartilhar o valor com a interface,\n\n\n uma vez que não é seguro fazer uma cópia do valor para o qual o ponteiro aponta.\n\n\n Se você escolheu implementar o método com semântica de ponteiro, você está afirmando\n\n\n que um valor desse tipo não é seguro para ser copiado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n u := user{\u0026#34;Bill\u0026#34;, \u0026#34;bill@email.com\u0026#34;}\n sendNotification(\u0026amp;u)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Para corrigir a mensagem do compilador, você deve usar a semântica de ponteiro\n\n\n na chamada para a função polimórfica e compartilhar u. A resposta não é mudar\n\n\n o método para usar a semântica de valor.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eSlice de Interface\u003c/h2\u003e\n \n \n \u003cp\u003e\n Ao declarar uma slice de um tipo interface, você é capaz de agrupar diferentes\n\n\n valores concretos com base no que eles podem fazer. É por isso que Go não precisa\n\n\n do conceito de subtipagem. Não se trata de um DNA comum, trata-se de um comportamento\n\n\n comum.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype printer interface {\n print()\n}\n\ntype canon struct {\n name string\n}\n\nfunc (c canon) print() {\n fmt.Printf(\u0026#34;Printer Name: %s\\n\u0026#34;, c.name)\n}\n\ntype epson struct {\n name string\n}\n\nfunc (e *epson) print() {\n fmt.Printf(\u0026#34;Printer Name: %s\\n\u0026#34;, e.name)\n}\n\nfunc main() {\n c := canon{\u0026#34;PIXMA TR4520\u0026#34;}\n e := epson{\u0026#34;WorkForce Pro WF-3720\u0026#34;}\n\n printers := []printer{\n c,\n \u0026amp;e,\n }\n c.name = \u0026#34;PROGRAF PRO-1000\u0026#34;\n e.name = \u0026#34;Home XP-4100\u0026#34;\n\n for _, p := range printers {\n p.print()\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ePrinter Name: PIXMA TR4520\nPrinter Name: Home XP-4100\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O código mostra como uma slice do tipo interface printer me permite criar uma\n\n\n coleção de diferentes tipos concretos de printer. Iterando a coleção e aproveitando\n\n\n o polimorfismo, já que a chamada para p.print muda seu comportamento dependendo\n\n\n do valor concreto para o qual o código está operando.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O exemplo também mostra como a escolha da semântica de dados muda o comportamento\n\n\n do programa. Ao armazenar os dados usando semântica de valor, a alteração no valor\n\n\n original não é vista. Isso ocorre porque uma cópia é armazenada dentro da interface.\n\n\n Quando a semântica de ponteiro é usada, quaisquer alterações no valor original são vistas.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eO conjunto de métodos de um valor inclui apenas os métodos implementados com um receiver de valor.\u003c/li\u003e\n \n \u003cli\u003eO conjunto de métodos de um ponteiro inclui os métodos implementados com receivers de ponteiro e de valor.\u003c/li\u003e\n \n \u003cli\u003eMétodos declarados com um receiver de ponteiro, implementam apenas a interface com valores de ponteiro.\u003c/li\u003e\n \n \u003cli\u003eMétodos declarados com um receiver de valor, implementam a interface tanto com um receiver de valor quanto com um de ponteiro.\u003c/li\u003e\n \n \u003cli\u003eAs regras dos conjuntos de métodos se aplicam aos tipos interface.\u003c/li\u003e\n \n \u003cli\u003eInterfaces são tipos de referência, não compartilhe com um ponteiro.\u003c/li\u003e\n \n \u003cli\u003eÉ assim que criamos comportamento polimórfico em go.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eCitações\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u0026#34;Polimorfismo significa que você escreve um determinado programa e ele se comporta de maneira diferente dependendo dos dados em que opera.\u0026#34; - Tom Kurtz (inventor of BASIC)\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;A interface vazia não diz nada.\u0026#34; - Rob Pike\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Design é a arte de organizar o código para funcionar hoje, e ser mutável para sempre.\u0026#34; - Sandi Metz\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Uma abstração adequada desacopla o código para que cada alteração não ecoe por toda a base de código.\u0026#34; - Ronna Steinburg\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/doc/effective_go.html#interfaces\" target=\"_blank\"\u003eInterfaces\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/laws-of-reflection\" target=\"_blank\"\u003eThe Laws of Reflection\u003c/a\u003e - Rob Pike \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/05/methods-interfaces-and-embedded-types.html\" target=\"_blank\"\u003eMethods, Interfaces and Embedded Types in Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://rakyll.org/interface-pollution/\" target=\"_blank\"\u003eInterface Pollution\u003c/a\u003e - JBD \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://bravenewgeek.com/abstraction-considered-harmful/\" target=\"_blank\"\u003eAbstraction Considered Harmful\u003c/a\u003e - Tyler Treat \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2018/03/interface-values-are-valueless.html\" target=\"_blank\"\u003eInterface Values Are Valueless\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2017/07/interface-semantics.html\" target=\"_blank\"\u003eInterface Semantics\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.hyrumslaw.com/\" target=\"_blank\"\u003eHyrum\u0026#39;s Law\u003c/a\u003e - Hyrum \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=Pjz9WrXeOW0\" target=\"_blank\"\u003eEngineering Innovation - Why Constraints Are Critical\u003c/a\u003e - André Eriksson (MUST WATCH)\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program that could benefit from polymorphic behavior with interfaces.\npackage main\n\nimport \"fmt\"\n\n// file defines a system file.\ntype file struct {\n\tname string\n}\n\n// read implements the reader interface for a file.\nfunc (file) read(b []byte) (int, error) {\n\ts := \"\u003crss\u003e\u003cchannel\u003e\u003ctitle\u003eGoing Go Programming\u003c/title\u003e\u003c/channel\u003e\u003c/rss\u003e\"\n\tcopy(b, s)\n\treturn len(s), nil\n}\n\n// pipe defines a named pipe network connection.\ntype pipe struct {\n\tname string\n}\n\n// read implements the reader interface for a network connection.\nfunc (pipe) read(b []byte) (int, error) {\n\ts := `{name: \"bill\", title: \"developer\"}`\n\tcopy(b, s)\n\treturn len(s), nil\n}\n\nfunc main() {\n\n\t// Create two values one of type file and one of type pipe.\n\tf := file{\"data.json\"}\n\tp := pipe{\"cfg_service\"}\n\n\t// Call each retrieve function for each concrete type.\n\tretrieveFile(f)\n\tretrievePipe(p)\n}\n\n// retrieveFile can read from a file and process the data.\nfunc retrieveFile(f file) error {\n\tdata := make([]byte, 100)\n\n\tlen, err := f.read(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Println(string(data[:len]))\n\treturn nil\n}\n\n// retrievePipe can read from a pipe and process the data.\nfunc retrievePipe(p pipe) error {\n\tdata := make([]byte, 100)\n\n\tlen, err := p.read(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Println(string(data[:len]))\n\treturn nil\n}\n","Hash":"MtGV+ylLTPGWf9ajuCRZbXGicYQ="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how polymorphic behavior with interfaces.\npackage main\n\nimport \"fmt\"\n\n// reader is an interface that defines the act of reading data.\ntype reader interface {\n\tread(b []byte) (int, error)\n}\n\n// file defines a system file.\ntype file struct {\n\tname string\n}\n\n// read implements the reader interface for a file.\nfunc (file) read(b []byte) (int, error) {\n\ts := \"\u003crss\u003e\u003cchannel\u003e\u003ctitle\u003eGoing Go Programming\u003c/title\u003e\u003c/channel\u003e\u003c/rss\u003e\"\n\tcopy(b, s)\n\treturn len(s), nil\n}\n\n// pipe defines a named pipe network connection.\ntype pipe struct {\n\tname string\n}\n\n// read implements the reader interface for a network connection.\nfunc (pipe) read(b []byte) (int, error) {\n\ts := `{name: \"bill\", title: \"developer\"}`\n\tcopy(b, s)\n\treturn len(s), nil\n}\n\nfunc main() {\n\n\t// Create two values one of type file and one of type pipe.\n\tf := file{\"data.json\"}\n\tp := pipe{\"cfg_service\"}\n\n\t// Call the retrieve function for each concrete type.\n\tretrieve(f)\n\tretrieve(p)\n}\n\n// retrieve can read any device and process the data.\nfunc retrieve(r reader) error {\n\tdata := make([]byte, 100)\n\n\tlen, err := r.read(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Println(string(data[:len]))\n\treturn nil\n}\n","Hash":"vQ23YgSP5WxiDxdOEGaXfKaAz5k="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to understand method sets.\npackage main\n\nimport \"fmt\"\n\n// notifier is an interface that defines notification\n// type behavior.\ntype notifier interface {\n\tnotify()\n}\n\n// user defines a user in the program.\ntype user struct {\n\tname string\n\temail string\n}\n\n// notify implements the notifier interface with a pointer receiver.\nfunc (u *user) notify() {\n\tfmt.Printf(\"Sending User Email To %s\u003c%s\u003e\\n\",\n\t\tu.name,\n\t\tu.email)\n}\n\nfunc main() {\n\n\t// Create a value of type User and send a notification.\n\tu := user{\"Bill\", \"bill@email.com\"}\n\n\t// Values of type user do not implement the interface because pointer\n\t// receivers don't belong to the method set of a value.\n\n\tsendNotification(u)\n\n\t// ./example1.go:36: cannot use u (type user) as type notifier in argument to sendNotification:\n\t// user does not implement notifier (notify method has pointer receiver)\n}\n\n// sendNotification accepts values that implement the notifier\n// interface and sends notifications.\nfunc sendNotification(n notifier) {\n\tn.notify()\n}\n","Hash":"MmedYFHTvmCUO7F79d2mk4nnDnM="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how you can't always get the address of a value.\npackage main\n\nimport \"fmt\"\n\n// duration is a named type with a base type of int.\ntype duration int\n\n// notify implements the notifier interface.\nfunc (d *duration) notify() {\n\tfmt.Println(\"Sending Notification in\", *d)\n}\n\nfunc main() {\n\tduration(42).notify()\n\n\t// ./example3.go:18: cannot call pointer method on duration(42)\n\t// ./example3.go:18: cannot take the address of duration(42)\n}\n","Hash":"HQrJIZ0J6Qc8qQEd6JQv05+ev0c="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how the concrete value assigned to\n// the interface is what is stored inside the interface.\npackage main\n\nimport \"fmt\"\n\n// printer displays information.\ntype printer interface {\n\tprint()\n}\n\n// cannon defines a cannon printer.\ntype cannon struct {\n\tname string\n}\n\n// print displays the printer's name.\nfunc (c cannon) print() {\n\tfmt.Printf(\"Printer Name: %s\\n\", c.name)\n}\n\n// epson defines a epson printer.\ntype epson struct {\n\tname string\n}\n\n// print displays the printer's name.\nfunc (e *epson) print() {\n\tfmt.Printf(\"Printer Name: %s\\n\", e.name)\n}\n\nfunc main() {\n\n\t// Create a cannon and epson printer.\n\tc := cannon{\"PIXMA TR4520\"}\n\te := epson{\"WorkForce Pro WF-3720\"}\n\n\t// Add the printers to the collection using both\n\t// value and pointer semantics.\n\tprinters := []printer{\n\n\t\t// Store a copy of the cannon printer value.\n\t\tc,\n\n\t\t// Store a copy of the epson printer value's address.\n\t\t\u0026e,\n\t}\n\n\t// Change the name field for both printers.\n\tc.name = \"PROGRAF PRO-1000\"\n\te.name = \"Home XP-4100\"\n\n\t// Iterate over the slice of printers and call\n\t// print against the copied interface value.\n\tfor _, p := range printers {\n\t\tp.print()\n\t}\n\n\t// When we store a value, the interface value has its own\n\t// copy of the value. Changes to the original value will\n\t// not be seen.\n\n\t// When we store a pointer, the interface value has its own\n\t// copy of the address. Changes to the original value will\n\t// be seen.\n}\n","Hash":"LO/QjoD8DBpC6HQNPYQjP2tI5EY="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show the syntax of type assertions.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n)\n\n// user defines a user in our application.\ntype user struct {\n\tid int\n\tname string\n}\n\n// finder represents the ability to find users.\ntype finder interface {\n\tfind(id int) (*user, error)\n}\n\n// userSVC is a service for dealing with users.\ntype userSVC struct {\n\thost string\n}\n\n// find implements the finder interface using pointer semantics.\nfunc (*userSVC) find(id int) (*user, error) {\n\treturn \u0026user{id: id, name: \"Anna Walker\"}, nil\n}\n\nfunc main() {\n\tsvc := userSVC{\n\t\thost: \"localhost:3434\",\n\t}\n\n\tif err := run(\u0026svc); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n// run performs the find operation against the concrete data that\n// is passed into the call.\nfunc run(f finder) error {\n\tu, err := f.find(1234)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Printf(\"Found user %+v\\n\", u)\n\n\t// Ideally the finder abstraction would encompass all of\n\t// the behavior you care about. But what if, for some reason,\n\t// you really need to get to the concrete value stored inside\n\t// the interface?\n\n\t// Can you access the \"host\" field from the concrete userSVC type pointer\n\t// that is stored inside this interface variable? No, not directly.\n\t// All you know is the data has a method named \"find\".\n\t// ./example5.go:61:26: f.host undefined (type finder has no field or method host)\n\tlog.Println(\"queried\", f.host)\n\n\t// You can use a type assertion to get a copy of the userSVC pointer\n\t// that is stored inside the interface.\n\tsvc := f.(*userSVC)\n\tlog.Println(\"queried\", svc.host)\n\n\treturn nil\n}\n","Hash":"89x4vLkMOPAmjWR9VX+3gSaH68c="},{"Name":"example7.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show type assertions using the comma-ok idiom.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n)\n\n// user defines a user in our application.\ntype user struct {\n\tid int\n\tname string\n}\n\n// finder represents the ability to find users.\ntype finder interface {\n\tfind(id int) (*user, error)\n}\n\n// userSVC is a service for dealing with users.\ntype userSVC struct {\n\thost string\n}\n\n// find implements the finder interface using pointer semantics.\nfunc (*userSVC) find(id int) (*user, error) {\n\treturn \u0026user{id: id, name: \"Anna Walker\"}, nil\n}\n\n// mockSVC defines a mock service we will access.\ntype mockSVC struct{}\n\n// find implements the finder interface using pointer semantics.\nfunc (*mockSVC) find(id int) (*user, error) {\n\treturn \u0026user{id: id, name: \"Jacob Walker\"}, nil\n}\n\nfunc main() {\n\tvar svc mockSVC\n\n\tif err := run(\u0026svc); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc run(f finder) error {\n\tu, err := f.find(1234)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Printf(\"Found user %+v\\n\", u)\n\n\t// If the concrete type value stored inside the interface value is of the\n\t// type *userSVC, then \"ok\" will be true and \"svc\" will be a copy of the\n\t// pointer stored inside the interface.\n\tif svc, ok := f.(*userSVC); ok {\n\t\tlog.Println(\"queried\", svc.host)\n\t}\n\n\treturn nil\n}\n","Hash":"WTVchFbDMkXOXU0bcxtuSNoRcQs="},{"Name":"example8.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show the syntax and mechanics of type\n// switches and the empty interface.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// fmt.Println can be called with values of any type.\n\tfmt.Println(\"Hello, world\")\n\tfmt.Println(12345)\n\tfmt.Println(3.14159)\n\tfmt.Println(true)\n\n\t// How can we do the same?\n\tmyPrintln(\"Hello, world\")\n\tmyPrintln(12345)\n\tmyPrintln(3.14159)\n\tmyPrintln(true)\n\n\t// - An interface is satisfied by any piece of data when the data exhibits\n\t// the full method set of behavior defined by the interface.\n\t// - The empty interface defines no method set of behavior and therefore\n\t// requires no method by the data being stored.\n\n\t// - The empty interface says nothing about the data stored inside\n\t// the interface.\n\t// - Checks would need to be performed at runtime to know anything about\n\t// the data stored in the empty interface.\n\t// - Decouple around well defined behavior and only use the empty\n\t// interface as an exception when it is reasonable and practical to do so.\n}\n\nfunc myPrintln(a interface{}) {\n\tswitch v := a.(type) {\n\tcase string:\n\t\tfmt.Printf(\"Is string : type(%T) : value(%s)\\n\", v, v)\n\tcase int:\n\t\tfmt.Printf(\"Is int : type(%T) : value(%d)\\n\", v, v)\n\tcase float64:\n\t\tfmt.Printf(\"Is float64 : type(%T) : value(%f)\\n\", v, v)\n\tdefault:\n\t\tfmt.Printf(\"Is unknown : type(%T) : value(%v)\\n\", v, v)\n\t}\n}\n","Hash":"/Zn24hUozDGbKMbNXA8SfkvNMm4="},{"Name":"example9.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program that explores how interface assignments work when\n// values are stored inside the interface.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"unsafe\"\n)\n\n// notifier provides support for notifying events.\ntype notifier interface {\n\tnotify()\n}\n\n// user represents a user in the system.\ntype user struct {\n\tname string\n}\n\n// notify implements the notifier interface.\nfunc (u user) notify() {\n\tfmt.Println(\"Alert\", u.name)\n}\n\nfunc inspect(n *notifier, u *user) {\n\tword := uintptr(unsafe.Pointer(n)) + uintptr(unsafe.Sizeof(\u0026u))\n\tvalue := (**user)(unsafe.Pointer(word))\n\tfmt.Printf(\"Addr User: %p Word Value: %p Ptr Value: %v\\n\", u, *value, **value)\n}\n\nfunc main() {\n\n\t// Create a notifier interface and concrete type value.\n\tvar n1 notifier\n\tu := user{\"bill\"}\n\n\t// Store a copy of the user value inside the notifier\n\t// interface value.\n\tn1 = u\n\n\t// We see the interface has its own copy.\n\t// Addr User: 0x1040a120 Word Value: 0x10427f70 Ptr Value: {bill}\n\tinspect(\u0026n1, \u0026u)\n\n\t// Make a copy of the interface value.\n\tn2 := n1\n\n\t// We see the interface is sharing the same value stored in\n\t// the n1 interface value.\n\t// Addr User: 0x1040a120 Word Value: 0x10427f70 Ptr Value: {bill}\n\tinspect(\u0026n2, \u0026u)\n\n\t// Store a copy of the user address value inside the\n\t// notifier interface value.\n\tn1 = \u0026u\n\n\t// We see the interface is sharing the u variables value\n\t// directly. There is no copy.\n\t// Addr User: 0x1040a120 Word Value: 0x1040a120 Ptr Value: {bill}\n\tinspect(\u0026n1, \u0026u)\n}\n","Hash":"A532r/lS4W00rft4xiLK35TyKRo="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Declare uma interface chamada speaker com um método chamado speak. Declare\n\n\n uma struct chamada english que representa uma pessoa que fala inglês e declare uma struct\n\n\n chamada chinese para alguém que fala chinês. Implemente a interface speaker para cada\n\n\n struct usando receiver de valor e essas strings literais \u0026#34;Hello World\u0026#34; and \u0026#34;你好世界\u0026#34;.\n\n\n Declare uma variável do tipo speaker e atribua o endereço de um valor do tipo english\n\n\n e chame o método. Faça isso novamente para o valor do tipo chinese.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Adicione uma nova função chamada sayHello que aceita um valor do tipo speaker.\n\n\n Implemente essa função para chamar o método speak no valor da interface. Em seguida, crie novos\n\n\n valores de cada tipo e use a função.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare an interface named speaker with a method named speak. Declare a struct\n// named english that represents a person who speaks english and declare a struct named\n// chinese for someone who speaks chinese. Implement the speaker interface for each\n// struct using a value receiver and these literal strings \"Hello World\" and \"你好世界\".\n// Declare a variable of type speaker and assign the address of a value of type english\n// and call the method. Do it again for a value of type chinese.\n//\n// Add a new function named sayHello that accepts a value of type speaker.\n// Implement that function to call the speak method on the interface value. Then create\n// new values of each type and use the function.\npackage main\n\n// Add imports.\n\n// Declare the speaker interface with a single method called speak.\n\n// Declare an empty struct type named english.\n\n// Declare a method named speak for the english type\n// using a value receiver. \"Hello World\"\n\n// Declare an empty struct type named chinese.\n\n// Declare a method named speak for the chinese type\n// using a pointer receiver. \"你好世界\"\n\n// sayHello accepts values of the speaker type.\nfunc sayHello( /* Declare parameter */ ) {\n\n\t// Call the speak method from the speaker parameter.\n}\n\nfunc main() {\n\n\t// Declare a variable of the interface speaker type\n\t// set to its zero value.\n\n\t// Declare a variable of type english.\n\n\t// Assign the english value to the speaker variable.\n\n\t// Call the speak method against the speaker variable.\n\n\t// Declare a variable of type chinese.\n\n\t// Assign the chinese pointer to the speaker variable.\n\n\t// Call the speak method against the speaker variable.\n\n\t// Call the sayHello function with new values and pointers\n\t// of english and chinese.\n}\n","Hash":"40l6NxzMGqMaXtoawen1Mu33lm0="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare an interface named speaker with a method named speak. Declare a struct\n// named english that represents a person who speaks english and declare a struct named\n// chinese for someone who speaks chinese. Implement the speaker interface for each\n// struct using a value receiver and these literal strings \"Hello World\" and \"你好世界\".\n// Declare a variable of type speaker and assign the address of a value of type english\n// and call the method. Do it again for a value of type chinese.\n//\n// Add a new function named sayHello that accepts a value of type speaker.\n// Implement that function to call the speak method on the interface value. Then create\n// new values of each type and use the function.\npackage main\n\nimport \"fmt\"\n\n// speaker implements the voice of anyone.\ntype speaker interface {\n\tspeak()\n}\n\n// english represents an english speaking person.\ntype english struct{}\n\n// speak implements the speaker interface using a\n// value receiver.\nfunc (english) speak() {\n\tfmt.Println(\"Hello World\")\n}\n\n// chinese represents a chinese speaking person.\ntype chinese struct{}\n\n// speak implements the speaker interface using a\n// pointer receiver.\nfunc (*chinese) speak() {\n\tfmt.Println(\"你好世界\")\n}\n\nfunc main() {\n\n\t// Declare a variable of the interface speaker type\n\t// set to its zero value.\n\tvar sp speaker\n\n\t// Declare a variable of type english.\n\tvar e english\n\n\t// Assign the english value to the speaker variable.\n\tsp = e\n\n\t// Call the speak method against the speaker variable.\n\tsp.speak()\n\n\t// Declare a variable of type chinese.\n\tvar c chinese\n\n\t// Assign the chinese pointer to the speaker variable.\n\tsp = \u0026c\n\n\t// Call the speak method against the speaker variable.\n\tsp.speak()\n\n\t// Call the sayHello function with new values and pointers\n\t// of english and chinese.\n\tsayHello(english{})\n\tsayHello(\u0026english{})\n\tsayHello(\u0026chinese{})\n\n\t// Why does this not work?\n\t// sayHello(chinese{})\n}\n\n// sayHello abstracts speaking functionality.\nfunc sayHello(sp speaker) {\n\tsp.speak()\n}\n","Hash":"Kue+3BwryhGgKrCd4yIGXiTPBts="}]}]} ,"maps":{"Title":"Maps","Description":"O `map` é uma estrutura de dados que suporta armazenamento e acesso aos dados utilizando uma chave.","Pages":[{"Title":"Maps","Content":"\n \u003ch2\u003eMaps\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O \u003ccode\u003emap\u003c/code\u003e é uma estrutura de dados que suporta armazenamento e acesso aos dados utilizando uma chave. \n\n\n Ele utiliza um `hash map` e o `bucket system` que mantém um bloco contínuo de memória subjacente.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declare, escreva, leia e delete\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Chaves ausentes\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Restrição de chave em Maps\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e \u003ccode\u003eMap\u003c/code\u003e literal e intervalos\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Ordenando \u003ccode\u003emaps\u003c/code\u003e por chave\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e Retornando o endereço de um elemento\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e7:\u003c/b\u003e \u003ccode\u003eMaps\u003c/code\u003e são do tipo Referencia\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eDeclarando e Construindo `Maps`\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declaração e construção de \u003ccode\u003emaps\u003c/code\u003e podem ser feitas de várias maneiras.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype user struct {\n name string\n username string\n}\n\n// Construa um `map` e atribua o seu valor como zero,\n// esse `map` pode armazenar tipo `user` por valor com uma chave do tipo `string`.\n// Tentar usar esse `map` resultara em um erro de execução (`panic`)\nvar users map[string]user\n\n// Construa e inicialize um `map` utilizando a função `make`,\n// esse `map` pode armazenar tipo `user` por valor com uma chave do tipo `string`.\nusers := make(map[string]user)\n\n// Construa e inicialize um `map` utilizando o construtor literal vazio ,\n// esse `map` pode armazenar tipo `user` por valor com uma chave do tipo `string`.\nusers := map[string]user{}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Um \u003ccode\u003emap\u003c/code\u003e inicializado para o valor zero não é utilizável e resultará em seu programa terminando por erro.\n\n\n O uso da função interna \u003ccode\u003emake\u003c/code\u003e e construção literal gera um \u003ccode\u003emap\u003c/code\u003e pronto para o uso.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n users := make(map[string]user)\n\n users[\u0026#34;Roy\u0026#34;] = user{\u0026#34;Rob\u0026#34;, \u0026#34;Roy\u0026#34;}\n users[\u0026#34;Ford\u0026#34;] = user{\u0026#34;Henry\u0026#34;, \u0026#34;Ford\u0026#34;}\n users[\u0026#34;Mouse\u0026#34;] = user{\u0026#34;Mickey\u0026#34;, \u0026#34;Mouse\u0026#34;}\n users[\u0026#34;Jackson\u0026#34;] = user{\u0026#34;Michael\u0026#34;, \u0026#34;Jackson\u0026#34;}\n\n for key, value := range users {\n fmt.Println(key, value)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eRoy {Rob Roy}\nFord {Henry Ford}\nMouse {Mickey Mouse}\nJackson {Michael Jackson}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Se a função interna \u003ccode\u003emake\u003c/code\u003e é usada para construir um \u003ccode\u003emap\u003c/code\u003e, então o operador de atribuição \n\n\n pode ser usado para adicionar e atualizar valores no \u003ccode\u003emap\u003c/code\u003e. A ordem em que as chaves/valores são retornados\n\n\n ao iterar sobre um \u003ccode\u003emap\u003c/code\u003e não é definida pela especificação e fica a cargo do compilador para implementar. \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n users := map[string]user{\n \u0026#34;Roy\u0026#34;: {\u0026#34;Rob\u0026#34;, \u0026#34;Roy\u0026#34;},\n \u0026#34;Ford\u0026#34;: {\u0026#34;Henry\u0026#34;, \u0026#34;Ford\u0026#34;},\n \u0026#34;Mouse\u0026#34;: {\u0026#34;Mickey\u0026#34;, \u0026#34;Mouse\u0026#34;},\n \u0026#34;Jackson\u0026#34;: {\u0026#34;Michael\u0026#34;, \u0026#34;Jackson\u0026#34;},\n }\n\n for key, value := range users {\n fmt.Println(key, value)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eFord {Henry Ford}\nJackson {Michael Jackson}\nRoy {Rob Roy}\nMouse {Mickey Mouse}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Nesse caso, o resultado foi retornado em uma ordem diferente da listada no construtor.\n\n\n O algoritmo utilizado pela versão 1.16 retorna os resultados em uma sequencia randômica \n\n\n uma vez que os valores atinjam um certo limite. Novamente, essa é a implementação do compilador\n\n\n e ela pode mudar. Você não pode depender dela. \n \u003c/p\u003e\n \n\n\n \u003ch2\u003eBusca e Deleção de Chaves de `Maps`\u003c/h2\u003e\n \n \n \u003cp\u003e\n Uma vez que o dado é armazenado dentro de um \u003ccode\u003emap\u003c/code\u003e, para extrair qualquer dado uma chave de busca é necessária.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003euser1, exists1 := users[\u0026#34;Bill\u0026#34;]\nuser2, exists2 := users[\u0026#34;Ford\u0026#34;]\n\nfmt.Println(\u0026#34;Bill:\u0026#34;, exists1, user1)\nfmt.Println(\u0026#34;Ford:\u0026#34;, exists2, user2)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eBill: false { }\nFord: true {Henry Ford}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Para executar uma busca por chave, colchetes são usados com a variável do tipo \u003ccode\u003emap\u003c/code\u003e.\n\n\n Dois valores podem ser retornados pela busca do \u003ccode\u003emap\u003c/code\u003e, o valor e um booleano que representa se o valor foi encontrado ou não.\n\n\n Se você não precisa disso agora, então você pode não utilizar a variável \u003ccode\u003eexists\u003c/code\u003e. \n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando a chave não é encontrada no \u003ccode\u003emap\u003c/code\u003e, a operação retorna o valor do tipo do \u003ccode\u003emap\u003c/code\u003e \n\n\n com o seu valor zerado. Você pode ver isso na busca usando \u0026#34;Bill\u0026#34; como chave. \n\n\n Não use o valor zerado para determinar se a chave existe ou não no \u003ccode\u003emap\u003c/code\u003e, uma vez que o \n\n\n valor zerado pode ser um valor válido que foi adicionado para uma chave. \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003edelete(users, \u0026#34;Roy\u0026#34;)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Existe uma função interna chamada \u003ccode\u003edelete\u003c/code\u003e que permite apagar registro de um \u003ccode\u003emap\u003c/code\u003e baseado em uma chave.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eRestrições de Chaves em `Maps`\u003c/h2\u003e\n \n \n \u003cp\u003e\n Nem todos os tipos podem ser usados como chave.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype slice []user\nUsers := make(map[slice]user)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Erro de compilação:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003einvalid map key type users\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A \u003ccode\u003eslice\u003c/code\u003e é um ótimo exemplo de tipo que não pode ser usado como uma chave. Somente\n\n\n valores que podem ser passados para a função \u003ccode\u003ehash\u003c/code\u003e são elegíveis. Uma boa forma de reconhecer\n\n\n tipos que podem ser utilizados como chave é se o tipo pode ser usado em uma operação de comparação.\n\n\n O valor de duas \u003ccode\u003eslices\u003c/code\u003e não podem ser comparados. \n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ccode\u003eMaps\u003c/code\u003e fornecem uma maneira de armazenar e recuperar pares chave/valor.\u003c/li\u003e\n \n \u003cli\u003eLendo uma chave ausente, retorna o valor zero para o tipo de valor do map.\u003c/li\u003e\n \n \u003cli\u003eIterar sobre um \u003ccode\u003emap\u003c/code\u003e é sempre de aleatório.\u003c/li\u003e\n \n \u003cli\u003eA chave de um \u003ccode\u003emap\u003c/code\u003e tem que ser um valor que possa ser comparado.\u003c/li\u003e\n \n \u003cli\u003eElementos de um \u003ccode\u003emap\u003c/code\u003e não podem ser endereçados.\u003c/li\u003e\n \n \u003cli\u003e\u003ccode\u003eMaps\u003c/code\u003e são um tipo por referencia. \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLinks\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://blog.golang.org/go-maps-in-action\" target=\"_blank\"\u003eGo maps in action\u003c/a\u003e - Andrew Gerrand \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/12/macro-view-of-map-internals-in-go.html\" target=\"_blank\"\u003eMacro View of Map Internals In Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=Tl7mi9QmLns\" target=\"_blank\"\u003eInside the Map Implementation\u003c/a\u003e - Keith Randall \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics\" target=\"_blank\"\u003eHow the Go runtime implements maps efficiently (without generics)\u003c/a\u003e - Dave Cheney \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to initialize a map, write to\n// it, then read and delete from it.\npackage main\n\nimport \"fmt\"\n\n// user represents someone using the program.\ntype user struct {\n\tname string\n\tsurname string\n}\n\nfunc main() {\n\n\t// Declare and make a map that stores values\n\t// of type user with a key of type string.\n\tusers := make(map[string]user)\n\n\t// Add key/value pairs to the map.\n\tusers[\"Roy\"] = user{\"Rob\", \"Roy\"}\n\tusers[\"Ford\"] = user{\"Henry\", \"Ford\"}\n\tusers[\"Mouse\"] = user{\"Mickey\", \"Mouse\"}\n\tusers[\"Jackson\"] = user{\"Michael\", \"Jackson\"}\n\n\t// Read the value at a specific key.\n\tmouse := users[\"Mouse\"]\n\n\tfmt.Printf(\"%+v\\n\", mouse)\n\n\t// Replace the value at the Mouse key.\n\tusers[\"Mouse\"] = user{\"Jerry\", \"Mouse\"}\n\n\t// Read the Mouse key again.\n\tfmt.Printf(\"%+v\\n\", users[\"Mouse\"])\n\n\t// Delete the value at a specific key.\n\tdelete(users, \"Roy\")\n\n\t// Check the length of the map. There are only 3 elements.\n\tfmt.Println(len(users))\n\n\t// It is safe to delete an absent key.\n\tdelete(users, \"Roy\")\n\n\tfmt.Println(\"Goodbye.\")\n}\n","Hash":"ozw9uwbvkWN4T0bKh0fcA07WSes="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how maps behave when you read an\n// absent key.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Create a map to track scores for players in a game.\n\tscores := make(map[string]int)\n\n\t// Read the element at key \"anna\". It is absent so we get\n\t// the zero-value for this map's value type.\n\tscore := scores[\"anna\"]\n\n\tfmt.Println(\"Score:\", score)\n\n\t// If we need to check for the presence of a key we use\n\t// a 2 variable assignment. The 2nd variable is a bool.\n\tscore, ok := scores[\"anna\"]\n\n\tfmt.Println(\"Score:\", score, \"Present:\", ok)\n\n\t// We can leverage the zero-value behavior to write\n\t// convenient code like this:\n\tscores[\"anna\"]++\n\n\t// Without this behavior we would have to code in a\n\t// defensive way like this:\n\tif n, ok := scores[\"anna\"]; ok {\n\t\tscores[\"anna\"] = n + 1\n\t} else {\n\t\tscores[\"anna\"] = 1\n\t}\n\n\tscore, ok = scores[\"anna\"]\n\tfmt.Println(\"Score:\", score, \"Present:\", ok)\n}\n","Hash":"X3kSd6syB9eVKlv061A/TDcARRs="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how only types that can have\n// equality defined on them can be a map key.\npackage main\n\nimport \"fmt\"\n\n// user represents someone using the program.\ntype user struct {\n\tname string\n\tsurname string\n}\n\n// users defines a set of users.\ntype users []user\n\nfunc main() {\n\n\t// Declare and make a map that uses a slice as the key.\n\tu := make(map[users]int)\n\n\t// ./example3.go:22: invalid map key type users\n\n\t// Iterate over the map.\n\tfor key, value := range u {\n\t\tfmt.Println(key, value)\n\t}\n}\n","Hash":"4TPX8/Sp5BsqapuS4iidObArgRA="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare, initialize and iterate\n// over a map. Shows how iterating over a map is random.\npackage main\n\nimport \"fmt\"\n\n// user represents someone using the program.\ntype user struct {\n\tname string\n\tsurname string\n}\n\nfunc main() {\n\n\t// Declare and initialize the map with values.\n\tusers := map[string]user{\n\t\t\"Roy\": {\"Rob\", \"Roy\"},\n\t\t\"Ford\": {\"Henry\", \"Ford\"},\n\t\t\"Mouse\": {\"Mickey\", \"Mouse\"},\n\t\t\"Jackson\": {\"Michael\", \"Jackson\"},\n\t}\n\n\t// Iterate over the map printing each key and value.\n\tfor key, value := range users {\n\t\tfmt.Println(key, value)\n\t}\n\n\tfmt.Println()\n\n\t// Iterate over the map printing just the keys.\n\t// Notice the results are different.\n\tfor key := range users {\n\t\tfmt.Println(key)\n\t}\n}\n","Hash":"1Cg+pyTzXDd9eSrR3BCixW1fD24="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to walk through a map by\n// alphabetical key order.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\n// user represents someone using the program.\ntype user struct {\n\tname string\n\tsurname string\n}\n\nfunc main() {\n\n\t// Declare and initialize the map with values.\n\tusers := map[string]user{\n\t\t\"Roy\": {\"Rob\", \"Roy\"},\n\t\t\"Ford\": {\"Henry\", \"Ford\"},\n\t\t\"Mouse\": {\"Mickey\", \"Mouse\"},\n\t\t\"Jackson\": {\"Michael\", \"Jackson\"},\n\t}\n\n\t// Pull the keys from the map.\n\tvar keys []string\n\tfor key := range users {\n\t\tkeys = append(keys, key)\n\t}\n\n\t// Sort the keys alphabetically.\n\tsort.Strings(keys)\n\n\t// Walk through the keys and pull each value from the map.\n\tfor _, key := range keys {\n\t\tfmt.Println(key, users[key])\n\t}\n}\n","Hash":"IPSHDOx+xm6Qp29YHqcItDpjpsY="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show that you cannot take the address\n// of an element in a map.\npackage main\n\n// player represents someone playing our game.\ntype player struct {\n\tname string\n\tscore int\n}\n\nfunc main() {\n\n\t// Declare a map with initial values using a map literal.\n\tplayers := map[string]player{\n\t\t\"anna\": {\"Anna\", 42},\n\t\t\"jacob\": {\"Jacob\", 21},\n\t}\n\n\t// Trying to take the address of a map element fails.\n\tanna := \u0026players[\"anna\"]\n\tanna.score++\n\n\t// ./example4.go:23:10: cannot take the address of players[\"anna\"]\n\n\t// Instead take the element, modify it, and put it back.\n\tplayer := players[\"anna\"]\n\tplayer.score++\n\tplayers[\"anna\"] = player\n}\n","Hash":"YGUt0if566M5YypaDFfhAZoxEcg="},{"Name":"example7.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how maps are reference types.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Initialize a map with values.\n\tscores := map[string]int{\n\t\t\"anna\": 21,\n\t\t\"jacob\": 12,\n\t}\n\n\t// Pass the map to a function to perform some mutation.\n\tdouble(scores, \"anna\")\n\n\t// See the change is visible in our map.\n\tfmt.Println(\"Score:\", scores[\"anna\"])\n}\n\n// double finds the score for a specific player and\n// multiplies it by 2.\nfunc double(scores map[string]int, player string) {\n\tscores[player] = scores[player] * 2\n}\n","Hash":"SddU6k+JgGZJfjANJKx04Cu5RY4="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declare e faça um \u003ccode\u003emap\u003c/code\u003e de valores inteiros tendo string como chave. \n\n\n Preencha o \u003ccode\u003emap\u003c/code\u003e com cinco valores e itere sobre o \u003ccode\u003emap\u003c/code\u003e para mostrar os pares chave/valor.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare and make a map of integer values with a string as the key. Populate the\n// map with five values and iterate over the map to display the key/value pairs.\npackage main\n\n// Add imports.\n\nfunc main() {\n\n\t// Declare and make a map of integer type values.\n\n\t// Initialize some data into the map.\n\n\t// Display each key/value pair.\n}\n","Hash":"PoSWCw/BHJ4kPAxNUSzsM13ZNf4="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare and make a map of integer values with a string as the key. Populate the\n// map with five values and iterate over the map to display the key/value pairs.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare and make a map of integer type values.\n\tdepartments := make(map[string]int)\n\n\t// Initialize some data into the map.\n\tdepartments[\"IT\"] = 20\n\tdepartments[\"Marketing\"] = 15\n\tdepartments[\"Executives\"] = 5\n\tdepartments[\"Sales\"] = 50\n\tdepartments[\"Security\"] = 8\n\n\t// Display each key/value pair.\n\tfor key, value := range departments {\n\t\tfmt.Printf(\"Dept: %s People: %d\\n\", key, value)\n\t}\n}\n","Hash":"zoAGUHlKI0Yk/YWIgmH4uaeDYNY="}]}]} ,"variables":{"Title":"Variáveis","Description":"Variáveis estão no coração da linguagem e fornecem a capacidade de ler e escrever na memória.","Pages":[{"Title":"Variáveis","Content":"\n \u003ch2\u003eVariáveis\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista o Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Variáveis estão no coração da linguagem e fornecem a capacidade de ler\n\n\n e escrever na memória. Em Go, o accesso à memória é \u0026#34;type safe\u0026#34;. Isso quer dizer que o compilador\n\n\n leva o tipo a sério e não nos permitirá usar variáveis fora do escopo\n\n\n que elas são declaradas.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1\u003c/b\u003e: Programa de exemplo que mostra como declarar variáveis.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eTipos Básicos\u003c/h2\u003e\n \n \n \u003cp\u003e\n Tipos fornecem integridade e legibilidade fazendo 2 perguntas:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eQual é a quantidade de memória a ser alocada? (por exemplo, 1, 2, 4, 8 bytes)\u003c/li\u003e\n \n \u003cli\u003eO que essa memória representa? (por exemplo, int, uint, bool,..)\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Tipos podem ser específicos para uma precisão como int32 ou int64:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003euint8 representa um inteiro sem sinal com 1 byte de alocação\u003c/li\u003e\n \n \u003cli\u003eint32 representa um inteiro com sinal com 4 bytes de alocação.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Quando você declara um tipo usando um tipo que não especifique precisão (uint, int), o tamanho do valor é baseado na\n\n\n arquitetura utilizada para compilar o programa.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eArquitetura de 32 bits: int representa um inteiro com sinal com 4 bytes de alocação de memória\u003c/li\u003e\n \n \u003cli\u003eArquitetura de 64 bits: int representa um inteiro com sinal com 8 bytes de alocação de memória\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eTamanho de Palavra\u003c/h2\u003e\n \n \n \u003cp\u003e\n O tamanho de palavra representa a quantidade de memória que deve ser alocada para armazenar\n\n\n inteiros e ponteiros em determinada arquitetura. Por exemplo:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eArquitetura de 32 bits: o tamanho da palavra é de 4 bytes de alocação de memória\u003c/li\u003e\n \n \u003cli\u003eArquitetura de 64 bits: o tamanho da palavra é de 8 bytes de alocação de memória\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Isso é importante porque Go possui estruturas de dados internas (maps, channels, slices,\n\n\n interfaces, e funções) que armazenam inteiros e ponteiros. O tamanho dessas estruturas\n\n\n de dados é baseado na arquitetura usada para compilar o programa.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Em Go, a quantidade de memória alocada para um valor do tipo int, um ponteiro, ou uma palavra\n\n\n será sempre a mesma na mesma arquitetura.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eConceito de Zero Value\u003c/h2\u003e\n \n \n \u003cp\u003e\n Cada valor que você constrói em Go é inicializado pelo menos no seu estado de \u0026#34;zero value\u0026#34;,\n\n\n a menos que você especifique o valor de inicilização na construção. O zero value é a configuração\n\n\n de cada bit em cada byte como zero.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Isso é feito para integridade dos dados e não é grátis. Leva tempo para empurrar\n\n\n elétrons através da máquina para redefinir esses bits, mas você deve sempre priorizar\n\n\n integridade em detrimento de desempenho.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eType Zero Value\nBoolean false\nInteger 0\nFloat 0\nComplex 0i\nString \u0026#34;\u0026#34; (empty)\nPointer nil\u003c/pre\u003e\n \n\n\n \u003ch2\u003eDeclaração e Inicialização\u003c/h2\u003e\n \n \n \u003cp\u003e\n A palavra var pode ser usada para construir valores em seu estado de zero value para todos os tipos.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar a int\nvar b string\nvar c float64\nvar d bool\n\nfmt.Printf(\u0026#34;var a int \\t %T [%v]\\n\u0026#34;, a, a)\nfmt.Printf(\u0026#34;var b string \\t %T [%v]\\n\u0026#34;, b, b)\nfmt.Printf(\u0026#34;var c float64 \\t %T [%v]\\n\u0026#34;, c, c)\nfmt.Printf(\u0026#34;var d bool \\t %T [%v]\\n\\n\u0026#34;, d, d)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar a int int [0]\nvar b string string []\nvar c float64 float64 [0]\nvar d bool bool [false]\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Strings usam o conjunto de caracteres UTF8, mas são apenas uma coleção de bytes.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Uma string é uma strutura de dados de duas palavras em Go:\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eA primeira palavra representa um ponteiro para um array de bytes de apoio\u003c/li\u003e\n \n \u003cli\u003eA segunda palavra representa o comprimento ou o número de bytes no array de apoio\u003c/li\u003e\n \n \u003cli\u003eSe a string estiver definida para seu zero value, então a primeira palavra é nil e a segunda palavra é 0.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Usando o operador de declaração de variávle curto, você pode declarar, construir, e\n\n\n inicializar um valor, tudo ao mesmo tempo.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eaa := 10 // int [10]\nbb := \u0026#34;hello\u0026#34; // string [hello]\ncc := 3.14159 // float64 [3.14159]\ndd := true // bool [true]\n\nfmt.Printf(\u0026#34;aa := 10 \\t %T [%v]\\n\u0026#34;, aa, aa)\nfmt.Printf(\u0026#34;bb := \\\u0026#34;hello\\\u0026#34; \\t %T [%v]\\n\u0026#34;, bb, bb)\nfmt.Printf(\u0026#34;cc := 3.14159 \\t %T [%v]\\n\u0026#34;, cc, cc)\nfmt.Printf(\u0026#34;dd := true \\t %T [%v]\\n\\n\u0026#34;, dd, dd)\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eaa := 10 int [10]\nbb := \u0026#34;hello\u0026#34; string [hello]\ncc := 3.14159 float64 [3.14159]\ndd := true bool [true]\u003c/pre\u003e\n \n\n\n \u003ch2\u003eConversão vs Casting\u003c/h2\u003e\n \n \n \u003cp\u003e\n Go não tem casting, mas sim conversão. Em vez de dizer para o compilador mapear\n\n\n um conjunto de bytes para uma representação diferente, os bytes precisam ser\n\n\n copiados para uma nova localização da memória para a nova representação.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eaaa := int32(10)\nfmt.Printf(\u0026#34;aaa := int32(10) %T [%v]\\n\u0026#34;, aaa, aaa)\n\nResultado:\naaa := int32(10) int32 [10]\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Go tem um pacote na biblioteca padrão chamado unsafe se você precisar executar uma\n\n\n operação de casting real. Você realmete deve evitar isso e ser honesto consigo mesmo\n\n\n sobre o por quê está considerando usá-lo. Fazer uma conversão fornece o nível mais alto\n\n\n de integridade para esses tipos de operações.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eO propósito de todos os programas e todas as partes desses programas é transformar dados de uma forma para outra.\u003c/li\u003e\n \n \u003cli\u003eCódigo primáriamente aloca, lê e grava na memória.\u003c/li\u003e\n \n \u003cli\u003eEntender tipo é crucial para escrever bom código e compreender código.\u003c/li\u003e\n \n \u003cli\u003eSe você não entende os dados, você não entende o problema.\u003c/li\u003e\n \n \u003cli\u003eVocê entende melhor o problema ao entender os dados.\u003c/li\u003e\n \n \u003cli\u003eQuando declarar variáveis com sues zero values, use a palavra var.\u003c/li\u003e\n \n \u003cli\u003eQuando declarar e inicializar variáveis, use o operador de declaração de variável curto.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/ref/spec#Boolean_types\" target=\"_blank\"\u003eTipos Básicos\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/doc/effective_go.html#variables\" target=\"_blank\"\u003eVariáveis\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2013/08/gustavos-ieee-754-brain-teaser.html\" target=\"_blank\"\u003eGustavo\u0026#39;s IEEE-754 Brain Teaser\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=sFUSP8Au_PE\" target=\"_blank\"\u003eWhat\u0026#39;s in a name\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://arcanesentiment.blogspot.com/2015/01/a-brief-history-of-type.html\" target=\"_blank\"\u003eA brief history of “type”\u003c/a\u003e - Arcane Sentiment \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// The playground is actually a 64-bit env with 32-bit pointers\n// The os/arch combo is named nacl/amd64p32\n\n// Sample program to show how to declare variables.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare variables that are set to their zero value.\n\tvar a int\n\tvar b string\n\tvar c float64\n\tvar d bool\n\n\tfmt.Printf(\"var a int \\t %T [%v]\\n\", a, a)\n\tfmt.Printf(\"var b string \\t %T [%v]\\n\", b, b)\n\tfmt.Printf(\"var c float64 \\t %T [%v]\\n\", c, c)\n\tfmt.Printf(\"var d bool \\t %T [%v]\\n\\n\", d, d)\n\n\t// Declare variables and initialize.\n\t// Using the short variable declaration operator.\n\taa := 10\n\tbb := \"hello\"\n\tcc := 3.14159\n\tdd := true\n\n\tfmt.Printf(\"aa := 10 \\t %T [%v]\\n\", aa, aa)\n\tfmt.Printf(\"bb := \\\"hello\\\" \\t %T [%v]\\n\", bb, bb)\n\tfmt.Printf(\"cc := 3.14159 \\t %T [%v]\\n\", cc, cc)\n\tfmt.Printf(\"dd := true \\t %T [%v]\\n\\n\", dd, dd)\n\n\t// Specify type and perform a conversion.\n\taaa := int32(10)\n\n\tfmt.Printf(\"aaa := int32(10) %T [%v]\\n\", aaa, aaa)\n}\n\n/*\n\tZero Values:\n\tType Initialized Value\n\tBoolean false\n\tInteger 0\n\tFloating Point 0\n\tComplex 0i\n\tString \"\" (empty string)\n\tPointer nil\n*/\n","Hash":"Jz8tOHBaIG3Y/qtBLfeDA+q+bkk="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o modelo como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eA:\u003c/b\u003e Declare três variáveis que são inicializadas com seu zero value e\n\n\n três declaradas com um valor literal. Declare variáveis do tipo string, int e bool.\n\n\n Exiba os valores dessas variáveis.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eParte\u003c/b\u003e \u003cb\u003eB:\u003c/b\u003e Declare uma nova variável do tipo float32 e inicialize a variável\n\n\n convertendo o valor literal de Pi (3.14).\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare three variables that are initialized to their zero value and three\n// declared with a literal value. Declare variables of type string, int and\n// bool. Display the values of those variables.\n//\n// Declare a new variable of type float32 and initialize the variable by\n// converting the literal value of Pi (3.14).\npackage main\n\n// Add imports\n\n// main is the entry point for the application.\nfunc main() {\n\n\t// Declare variables that are set to their zero value.\n\n\t// Display the value of those variables.\n\n\t// Declare variables and initialize.\n\t// Using the short variable declaration operator.\n\n\t// Display the value of those variables.\n\n\t// Perform a type conversion.\n\n\t// Display the value of that variable.\n}\n","Hash":"ZlFzQamBPuTIkjogQuPcbbPS/k4="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare three variables that are initialized to their zero value and three\n// declared with a literal value. Declare variables of type string, int and\n// bool. Display the values of those variables.\n//\n// Declare a new variable of type float32 and initialize the variable by\n// converting the literal value of Pi (3.14).\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare variables that are set to their zero value.\n\tvar age int\n\tvar name string\n\tvar legal bool\n\n\t// Display the value of those variables.\n\tfmt.Println(age)\n\tfmt.Println(name)\n\tfmt.Println(legal)\n\n\t// Declare variables and initialize.\n\t// Using the short variable declaration operator.\n\tmonth := 10\n\tdayOfWeek := \"Tuesday\"\n\thappy := true\n\n\t// Display the value of those variables.\n\tfmt.Println(month)\n\tfmt.Println(dayOfWeek)\n\tfmt.Println(happy)\n\n\t// Perform a type conversion.\n\tpi := float32(3.14)\n\n\t// Display the value of that variable.\n\tfmt.Printf(\"%T [%v]\\n\", pi, pi)\n}\n","Hash":"DM2Gkjg0Fknlwe/gt+enkT/ImB8="}]}]} ,"algorithms-searches":{"Title":"Operações de Busca","Description":"Esta seção fornece exemplos que realizam operações de busca.","Pages":[{"Title":"Busca Binária","Content":"\n \u003ch2\u003eBusca Binária\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao Vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira? Utilize o Nosso\u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n O programa de exemplo implementa uma função que realiza uma busca binária iterativa em um conjunto de números inteiros.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003eVeja mais em: \u003ca href=\"https://en.wikipedia.org/wiki/Binary_search_algorithm\" target=\"_blank\"\u003ehttps://en.wikipedia.org/wiki/Binary_search_algorithm\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDiagrama\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eA busca binária compara o valor alvo com o elemento do meio do `array`.\nSe eles não forem iguais, a metade na qual o alvo não pode estar é eliminada\ne a busca continua na metade restante, novamente pegando o elemento do meio\npara comparar com o valor alvo e repetindo esse processo até que o valor alvo\nseja encontrado. Se a busca terminar com a metade restante ficando vazia,\nsignifica que o alvo não está no array.\n\n┌────┐\n│ 83 │ ◁── Target Number\n└────┘\n┌────┐┌────┐┌────┐┌────┐┌────┐\n│ 04 ││ 42 ││ 80 ││ 83 ││ 95 │ ◁── Starting Array\n└────┘└────┘└────┘└────┘└────┘\n ┌────┐ ◁── Middle Value\n │ 80 │ ◁── Target Number Is Greater\n └────┘\n ┌────┐┌────┐\n │ 83 ││ 95 │ ◁── Search This Half\n └────┘└────┘\n ┌────┐\n │ 83 │ ◁── Middle Value\n └────┘\n ┌────┐\n │ 83 │ ◁── Target Found / Idx 3\n └────┘\u003c/pre\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n","Files":[{"Name":"binary_iterative.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a binary search using an\n// iterative approach.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tnumbers := []int{4, 42, 80, 83, 121, 137, 169, 182, 185, 180}\n\tfind := rand.Intn(10)\n\n\tfmt.Println(\"Numbers:\", numbers)\n\tfmt.Println(\"Find. :\", numbers[find])\n\n\tidx, err := binarySearchIterative(numbers, numbers[find])\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"Found : Idx\", idx)\n}\n\nfunc binarySearchIterative(sortedList []int, target int) (int, error) {\n\tvar leftIdx int\n\trightIdx := len(sortedList) - 1\n\n\t// Loop until we find the target or searched the list.\n\tfor leftIdx \u003c= rightIdx {\n\n\t\t// Calculate the middle index of the list.\n\t\tmid := (leftIdx + rightIdx) / 2\n\n\t\t// Capture the value to check.\n\t\tvalue := sortedList[mid]\n\n\t\tswitch {\n\n\t\t// Check if we found the target.\n\t\tcase value == target:\n\t\t\treturn mid, nil\n\n\t\t// If the value is greater than the target, cut the list\n\t\t// by moving the rightIdx into the list.\n\t\tcase value \u003e target:\n\t\t\trightIdx = mid - 1\n\n\t\t// If the value is less than the target, cut the list\n\t\t// by moving the leftIdx into the list.\n\t\tcase value \u003c target:\n\t\t\tleftIdx = mid + 1\n\t\t}\n\t}\n\n\treturn -1, fmt.Errorf(\"target not found\")\n}\n","Hash":"PyHQWydyvZRnQx07p5DWsx7qj7s="},{"Name":"binary_recursive.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// This sample program shows you how to write a binary search using a\n// recursive approach.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tnumbers := []int{4, 42, 80, 83, 121, 137, 169, 182, 185, 180}\n\tfind := rand.Intn(10)\n\n\tfmt.Println(\"Numbers:\", numbers)\n\tfmt.Println(\"Find. :\", numbers[find])\n\n\tidx, err := binarySearchRecursive(numbers, numbers[find], 0, len(numbers))\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"Found : Idx\", idx)\n}\n\nfunc binarySearchRecursive(sortedList []int, target int, leftIdx int, rightIdx int) (int, error) {\n\n\t// Calculate the middle index of the list.\n\tmidIdx := (leftIdx + rightIdx) / 2\n\n\t// Check until leftIdx is smaller or equal with rightIdx.\n\tif leftIdx \u003c= rightIdx {\n\n\t\tswitch {\n\n\t\t// Check if we found the target.\n\t\tcase sortedList[midIdx] == target:\n\t\t\treturn midIdx, nil\n\n\t\t// If the value is greater than the target, cut the list\n\t\t// by moving the rightIdx into the list.\n\t\tcase sortedList[midIdx] \u003e target:\n\t\t\treturn binarySearchRecursive(sortedList, target, leftIdx, midIdx-1)\n\n\t\t// If the value is less than the target, cut the list\n\t\t// by moving the leftIdx into the list.\n\t\tcase sortedList[midIdx] \u003c target:\n\t\t\treturn binarySearchRecursive(sortedList, target, midIdx+1, rightIdx)\n\t\t}\n\t}\n\n\treturn -1, fmt.Errorf(\"target not found\")\n}\n\nfunc generateList(totalNumbers int) []int {\n\tnumbers := make([]int, totalNumbers)\n\n\tfor i := 0; i \u003c totalNumbers; i++ {\n\t\tnumbers[i] = rand.Intn(totalNumbers * 20)\n\t}\n\n\treturn numbers\n}\n","Hash":"qLTFcJZ6ASJglaM6yUbqVLXl10I="}]}]} ,"arrays":{"Title":"Arrays","Description":"Arrays são um tipo especial de estrutura de dados em Go que permite a alocação contígua de blocos de memória de tamanho fixo.","Pages":[{"Title":"Arrays","Content":"\n \u003ch2\u003eArrays\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n Arrays são um tipo especial de estrutura de dados em Go que permite a alocação contígua de blocos de memória de tamanho fixo.\n\n\n Arrays tem características especiais em Go relacionadas a como eles são declarados e visualizados como tipos.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Declarar, inicializar e iterar\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Tipos diferentes de arrays\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Alocação de memória contígua\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Funcionamento de Range\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eDeclarando e Inicializando Valores\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declare um array de string com tamanho 5 inicializado com seu valor inicial padrão.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar strings [5]string\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Uma string é uma estrutura de dados imutável de duas palavras que representa um ponteiro para\n\n\n um array de bytes e o número total de bytes nesse array. Como esse array é definido com o valor inicial padrão,\n\n\n todos os seus elementos também são definidos com o seu valor inicial padrão. Isso significa que cada string tem \n\n\n a primeira palavra definida como nil e a segunda definida como 0.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/a1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/a1.png\"\u003e\n \u003c/a\u003e\n\n\n \u003ch2\u003eAtribuições de String\u003c/h2\u003e\n \n \n \u003cp\u003e\n O que acontece quando uma string é atribuída a outra string?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003estrings[0] = \u0026#34;Apple\u0026#34;\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando uma string é atribuída a outra string, o valor das duas palavras é copiado,\n\n\n resultando em duas strings com valores diferentes, mas ambos compartilhando o mesmo array de suporte.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/a2.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/a2.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n O custo para se copiar a string é o mesmo, independente do tamanho da string, o de copiar duas palavras.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eIterando sobre Collections\u003c/h2\u003e\n \n \n \u003cp\u003e\n Go tem duas semânticas diferentes para iterar sobre uma collection. Eu posso usar uma semântica baseada em valores ou ponteiros.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// Iteração usando valores\nfor i, fruit := range strings {\n println(i, fruit)\n}\n\n\n// Iteração usando ponteiros\nfor i := range strings {\n println(i, strings[i])\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando iteramos usando valor, duas coisas acontecem. Primeira, a collection inteira é copiada e você navega sobre a cópia.\n\n\n No caso de arrays, a cópia pode ser bem cara uma vez que o array inteiro é copiado. No caso de uma slice, não há um custo real\n\n\n uma vez que somente os valores internos da slice são copiados e não o array de suporte. Segundo, você recebe uma cópia de \n\n\n todos os elementos sendo iterados.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando iteramos usando ponteiros, você itera sobre a collection original e acessa diretamente cada elemento associado com a collection. \n \u003c/p\u003e\n \n\n\n \u003ch2\u003eIteração por valor\u003c/h2\u003e\n \n \n \u003cp\u003e\n Dado o seguinte código e seu resultado\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003estrings := [5]string{\u0026#34;Apple\u0026#34;, \u0026#34;Orange\u0026#34;, \u0026#34;Banana\u0026#34;, \u0026#34;Grape\u0026#34;, \u0026#34;Plum\u0026#34;}\nfor i, fruit := range strings {\n println(i, fruit)\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e0 Apple\n1 Orange\n2 Banana\n3 Grape\n4 Plum\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A variável strings é um array de tamanho 5 do tipo string. O loop passa por cada string da collection\n\n\n e mostra o índice da posição e o valor da string. Como essa iteração é por valor, o for range itera por uma shallow copy \n\n\n do array e cada iteração a variável fruit é uma cópia de cada string (a estrutura de dados de duas palavras).\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Perceba como a variável fruit é passada para a função print usando valores. A função print também está pegando \n\n\n sua própria cópia do valor da string. Quando a string é passada para a função print, temos 4 cópias do valor da \n\n\n string (array, shallow copy, variável fruit e a cópia para a função print). Todas as 4 cópias estão compartilhando \n\n\n o mesmo array de bytes.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/a3.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/a3.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Fazer cópias do valor da string é importante para prevenir que o valor da string acabe vazando para o heap. \n\n\n Isso elimina alocações desnecessárias do heap.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eIterações usando ponteiros\u003c/h2\u003e\n \n \n \u003cp\u003e\n Dado o seguinte código e resultado.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003estrings := [5]string{\u0026#34;Apple\u0026#34;, \u0026#34;Orange\u0026#34;, \u0026#34;Banana\u0026#34;, \u0026#34;Grape\u0026#34;, \u0026#34;Plum\u0026#34;}\nfor i := range strings {\n println(i, strings[i])\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e0 Apple\n1 Orange\n2 Banana\n3 Grape\n4 Plum\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Novamente, temos a variável strings como um array de tamanho 5 do tipo string. O loop itera \n\n\n por cada string na collection e mostra o índice da posição e o valor da string. Já que estamos usando \n\n\n ponteiros, o for range itera pelo array strings diretamente e a cada iteração o valor da string para \n\n\n cada índice é acessado diretamente pela chamada da função print. \n \u003c/p\u003e\n \n\n\n \u003ch2\u003eDiferentes tipo de Arrays\u003c/h2\u003e\n \n \n \u003cp\u003e\n É interessante ver qual o erro retornado pelo compilador quando atribuímos arrays \n\n\n do mesmo tipo mas com tamanhos diferentes. \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003evar five [5]int\nfour := [4]int{10, 20, 30, 40}\n\nfive = four\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Erro de Compilação:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003ecannot use four (type [4]int) as type [5]int in assignment\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui você vai declarar dois arrays do tipo integer de tamanhos 4 e 5 respectivamente, \n\n\n inicialize-os com seus valores inicial padrão. Agora tente atribuir um ao outro e o compilador vai dizer, \u0026#34;cannot use four\n\n\n (type [4]int) as type [5]int in assignment\u0026#34;.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n É importante que fique claro o que o compilador está dizendo. Ele diz que um array de 4 inteiros \n\n\n e um array de 5 inteiros representam informações de tipos diferentes. O tamanho do array faz parte \n\n\n da informação do seu tipo. Em Go, o tamanho de um array precisa ser conhecido durante a compilação.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eConstrução de Memória Contígua\u003c/h2\u003e\n \n \n \u003cp\u003e\n Você quer provar que um array usa memória contígua\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efive := [5]string{\u0026#34;Annie\u0026#34;, \u0026#34;Betty\u0026#34;, \u0026#34;Charley\u0026#34;, \u0026#34;Doug\u0026#34;, \u0026#34;Bill\u0026#34;}\n\nfor i, v := range five {\n fmt.Printf(\u0026#34;Value[%s]\\tAddress[%p] IndexAddr[%p]\\n\u0026#34;,\n v, \u0026amp;v, \u0026amp;five[i])\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Resultado:\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eValue[Annie] Address[0xc000010250] IndexAddr[0xc000052180]\nValue[Betty] Address[0xc000010250] IndexAddr[0xc000052190]\nValue[Charley] Address[0xc000010250] IndexAddr[0xc0000521a0]\nValue[Doug] Address[0xc000010250] IndexAddr[0xc0000521b0]\nValue[Bill] Address[0xc000010250] IndexAddr[0xc0000521c0]\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Aqui você declara um array com 5 strings inicializado com nomes. Agora itere \n\n\n por valores para mostrar as informações de cada string. O resultado mostra \n\n\n cada valor individual da string, o endereço da variável v e o endereço de cada \n\n\n elemento do array.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Note como o array é um bloco de memória contígua e como a string tem 2 palavras ou \n\n\n uma estrutura de dados de 16 bytes dentro da minha arquitetura de 64 bits.\n\n\n O endereço de cada elemento acontece em intervalos de 16 bytes.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O fato de que a variável v tenha o mesmo endereço em cada iteração, fortalece o \n\n\n entendimento de que v é uma variável local de tipo string que contém a cópia de \n\n\n cada valor da string durante a iteração.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eCache de CPU\u003c/h2\u003e\n \n \n \u003cp\u003e\n Existem várias mecânicas diferentes entre processadores e seus designes. Nesta seção, \n\n\n falaremos, em alto nível, sobre processadores e as semânticas que sao relativamente\n\n\n as mesmas entre todos eles. O entendimento dessa semântica te dará um bom modelo \n\n\n mental de como o processador funciona e a simpatia que você pode oferecer.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Cada core do processador tem sua própria memoria cache (L1 e L2) e uma memória cache \n\n\n comum (L3) usada para armazenar/acessar dados e instruções. Os threads de hardware em \n\n\n cada core podem acessar os seus caches locais L1 e L2. Dados vindos do cache L3 ou \n\n\n memória principal precisam ser copiados dentro de L1 e L2.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/a4.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/a4.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Os custos de latência para acessar informações em níveis diferentes de cache mudam do menor \n\n\n para o maior: L1 -\u0026gt; L2 -\u0026gt; L3 -\u0026gt; memória principal. Como dito por Scott Meyers, \u0026#34;Se Performance \n\n\n é importante, então o total de memória que você tem é a quantidade total de cache. \n\n\n A memória principal é lenta para se acessar, do jeito que ela poderia muito bem não estar lá\u0026#34;. \n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Atualmente, performance é sobre quão eficiente a informação trafega pelo hardware. Se toda a \n\n\n informação necessária pelo hardware precisasse, a qualquer momento, existir em memória, então \n\n\n meu programa seria mais lento comparado com a informação que já está presente nos caches L1 ou L2. \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e3GHz(3 ciclos de clock/ns) * 4 instruções por ciclo = 12 instruções por ns!\n\n1 ns ............. 1 ns .............. 12 instruções (unidade) \n1 µs ......... 1,000 ns .......... 12,000 instruções (milhares)\n1 ms ..... 1,000,000 ns ...... 12,000,000 instruções (milhões)\n1 s .. 1,000,000,000 ns .. 12,000,000,000 instruções (bilhões)\n\nLatências definidas pela industria\nReferência de cache de L1 ......................... 0.5 ns ................... 6 ins\nReferência de cache de L2 ........................... 7 ns ................... 84 ins\nReferência de Memória Principal ................... 100 ns ................. 1200 ins\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Como você escreve código que garanta que todas as informações necessárias para executar uma \n\n\n instrução estejam sempre presentes em caches de L1 ou L2? Você precisa escrever um código que\n\n\n seja mecanicamente compatível com o prefetcher do processador. O prefetcher tenta prever os \n\n\n dados necessários antes que as instruções precisem deles, para que assim, eles já estejam no \n\n\n cache de L1 ou L2.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Existem diferentes níveis de granularidade de acesso de memória dependendo de onde o \n\n\n acesso está vindo. Meu código pode ler e escrever um byte de memória como a menor \n\n\n unidade de memória a ser acessado. Porém, do ponto de vista do sistema de cache, a \n\n\n granularidade é de 64 bytes. Esses bloco de memória de 64 bytes é chamado de linha \n\n\n de cache.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O Prefetcher trabalha no seu melhor quando as instruções sendo executadas criam \n\n\n padrões previsíveis de acesso à memória. Uma maneira de criar padrões previsíveis \n\n\n de acesso à memória é construindo um bloco de memória contígua e iterar sobre essa memória\n\n\n realizando uma travessia linear com um passo previsível.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O array é a estrutura de dados mais importante para o hardware porque ele suporta padrões de \n\n\n acesso previsíveis. Porém, a slice é a estrutura de dados mais importante em Go. Slices em \n\n\n Go usam um array por trás.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Quando você constrói um array, todo elemento está igualmente distante do seu elementos anterior \n\n\n e seguinte. A medida que você itera um array, você começa a navegar de uma linha de cache para \n\n\n uma linha de cache conectada de forma previsível. O Prefetcher vai então se utilizar desse padrão \n\n\n de acesso previsível e irá, de forma eficiente, trazer os dados para o processador, reduzindo \n\n\n assim o custo de latência. \n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Imagine agora que você tem uma matriz quadrática de memória e uma lista encadeada com a mesma \n\n\n quantidade de nós que a matriz. Se você executar uma travessia na lista encadeada e na matriz \n\n\n em ambas as dimensões (Coluna e Linha), como vai ser a comparação de ambas as performances? \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc RowTraverse() int {\n var ctr int\n for row := 0; row \u0026lt; rows; row\u0026#43;\u0026#43; {\n for col := 0; col \u0026lt; cols; col\u0026#43;\u0026#43; {\n if matrix[row][col] == 0xFF {\n ctr\u0026#43;\u0026#43;\n }\n }\n }\n return ctr\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Travessia da Linha tem a melhor performance porque anda pela memória, linha de cache \n\n\n por linha de cache conectada, o que cria um padrão de acesso previsível. Linhas de cache \n\n\n podem ser pre-carregadas e copiada para cache de L1 ou L2 antes que os dados sejam \n\n\n necessários.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc ColumnTraverse() int {\n var ctr int\n for col := 0; col \u0026lt; cols; col\u0026#43;\u0026#43; {\n for row := 0; row \u0026lt; rows; row\u0026#43;\u0026#43; {\n if matrix[row][col] == 0xFF {\n ctr\u0026#43;\u0026#43;\n }\n }\n }\n return ctr\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A travessia da Coluna tem a pior performance por uma ordem de grandeza, porque esse \n\n\n padrão de acesso cruza os limites das páginas do sistema operacional a cada acesso à \n\n\n memória. Dessa forma é impossível pre-carregarmos as linhas de cache e virando basicamente \n\n\n um acesso aleatório de memória.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc LinkedListTraverse() int {\n var ctr int\n d := list\n for d != nil {\n if d.v == 0xFF {\n ctr\u0026#43;\u0026#43;\n }\n d = d.p\n }\n return ctr\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A lista encadeada é duas vezes mais lenta do que a travessia de linha, principalmente \n\n\n porque há falhas de linhas de cache, mas há menos falhas de TLB (Translation Lookaside \n\n\n Buffer). A maior parte dos nós conectados na lista existe dentro da mesma página do \n\n\n sistema operacional. \n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eBenchmarkLinkListTraverse-16 128 28738407 ns/op\nBenchmarkColumnTraverse-16 30 126878630 ns/op\nBenchmarkRowTraverse-16 310 11060883 ns/op\u003c/pre\u003e\n \n\n\n \u003ch2\u003eTranslation Lookaside Buffer (TLB)\u003c/h2\u003e\n \n \n \u003cp\u003e\n Cada programa em execução recebe um mapa completo da memória virtual do Sistema operacional\n\n\n e o programa pensa que ele tem toda a memória física da máquina. Porém, a memória física \n\n\n precisa ser compartilhada com todos os programas em execução. O sistema operacional \n\n\n compartilha a memória física dividindo-a em páginas e alocando essas páginas à programas \n\n\n em execução. Cada sistema operacional decide o tamanho dessas páginas, mas 4k, 8k e 16k \n\n\n são tamanhos razoáveis e comumente utilizados. \n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n O TLB é um pequeno cache dentro do processador que ajuda a reduzir a latência da tradução do \n\n\n endereço da memória virtual para o endereço da memória física dentro do escopo de uma página \n\n\n do sistema operacional e de seu descolamento dentro da página. Uma falha no cache TLB pode\n\n\n acarretar um aumento de latência porque o hardware tem que esperar o sistema operacional\n\n\n escanear sua tabela de páginas para localizar a página correta para esse endereço de memória \n\n\n virtual em questão. Se o programa está rodando dentro de uma máquina virtual (como rodando em uma nuvem)\n\n\n então a tabela de paginação da máquina virtual precisa ser escaneada antes.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Lembre-se do que eu disse:\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A lista encadeada é duas vezes mais lenta do que a travessia de linha, principalmente porque \n\n\n há falhas de linhas de cache, mas há menos falhas de TLB (explicarei a seguir). A maior parte \n\n\n dos nós conectados na lista existe dentro da mesma página do sistema operacional. \n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n A Lista Encadeada é mais rápida do que a travessia por coluna por algumas ordens de grandeza \n\n\n devido ao acesso ao TLB. Mesmo que haja falhas de linha de cache na travessia da lista encadeada, \n\n\n uma vez que a maioria da memória para um grupo de nós se encontra dentro da mesma página, \n\n\n as latências do TLB não afetam o desempenho. É por isso que, para programas que utilizam uma \n\n\n grande quantidade de memória, como aplicações baseadas em DNA, pode ser aconselhável usar uma\n\n\n distribuição do Linux configurada com tamanhos de página na ordem de um ou dois megabytes de \n\n\n memória.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Tendo dito isso, o design orientado a dados é importante. Para escrevermos um algoritmo eficiente \n\n\n precisamos levar em consideração como os dados são acessados. Lembre-se de que o desempenho hoje \n\n\n em dia está relacionado a quão eficientemente você pode inserir dados no processador.\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://youtu.be/WDIkqP4JbkE?t=1129\" target=\"_blank\"\u003eCPU Caches and Why You Care (18:50-20:30)\u003c/a\u003e - Scott Meyers \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://youtu.be/WDIkqP4JbkE?t=2676\" target=\"_blank\"\u003eCPU Caches and Why You Care (44:36-45:40)\u003c/a\u003e - Scott Meyers \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://youtu.be/jEG4Qyo_4Bc?t=266\" target=\"_blank\"\u003ePerformance Through Cache-Friendliness (4:25-5:48)\u003c/a\u003e - Damian Gryski \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eNotas sobre o cache de CPU\u003c/h2\u003e\n \u003cul\u003e\n\u003cli\u003eCaches de CPU funcionam armazenando a memória principal em linhas de cache.\u003c/li\u003e\n\u003cli\u003eLinhas de cache são de tamanho 32 ou 64 bytes dependendo do hardware.\u003c/li\u003e\n\u003cli\u003eNúcleos de processadores não acessam diretamente a memória principal. Eles tendem a ter acesso somente ao seu cache local.\u003c/li\u003e\n\u003cli\u003eAmbas as datas e instruções são armazenados nos caches.\u003c/li\u003e\n\u003cli\u003eLinhas de caches são movidas para L1-\u0026gt;L2-\u0026gt;L3 â medida que novas linhas de cache precisam ser armazenadas nos caches .\u003c/li\u003e\n\u003cli\u003eHardware gosta de percorrer dados e instruções de forma linear ao longo das linhas de cache.\u003c/li\u003e\n\u003cli\u003e\u003cp\u003eA memória principal é construída com memória relativamente rápida e barata. Os caches são construídos com memória muito rápida e cara.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003eO acesso à memória principal é incrivelmente lento, por isso precisamos da cache.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAcessar um byte na memória principal fará com que \numa linha de cache inteira seja lida e \narmazenada em cache.\u003c/li\u003e\n\u003cli\u003eEscrever um byte em uma linha de cache requer que \na linha de cache inteira seja escrita.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003ePequeno = Rápido\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCódigo compacto, bem localizado e que cabe na cache é o mais rápido.\u003c/li\u003e\n\u003cli\u003eEstruturas de dados compactas que cabem na cache são as mais rápidas.\u003c/li\u003e\n\u003cli\u003eTravessias que acessam apenas dados em cache são as mais rápidas.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003ePadrões de acesso previsíveis são importantes.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSempre que for possível, você deseja empregar uma travessia linear de array.\u003c/li\u003e\n\u003cli\u003eFornecer padrões regulares de acesso à memória.\u003c/li\u003e\n\u003cli\u003eO hardware pode fazer previsões melhores sobre a memória necessária.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003eFalhas de cache podem resultar em falhas de cache do TLB também.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCache de traduções de um endereço virtual para um endereço físico.\u003c/li\u003e\n\u003cli\u003eEsperar pelo sistema operacional nos dizer onde está a memória.\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\n\n \u003ch2\u003eDiagramas extra\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eLatências\u003c/b\u003e \u003cb\u003eDefinidas\u003c/b\u003e \u003cb\u003ePela\u003c/b\u003e \u003cb\u003eIndustria\u003c/b\u003e\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003eReferência de cache L1 ........................ 0.5 ns ................... 6 ins\nBranch mispredict ............................... 5 ns ................... 60 ins\nReferência de cache L2 ......................... 7 ns ................... 84 ins\nMutex lock/unlock .............................. 25 ns .................. 300 ins\nReferência da memória principal ............... 100 ns ................. 1200 ins \nComprimir 1K bytes com Zippy ................ 3,000 ns (3 µs) ........... 36k ins\nEnviar 2K bytes por uma rede de 1 Gbps...... 20,000 ns (20 µs) ........ 240k ins\nLeitura aleatória em SSD .................. 150,000 ns (150 µs) ........ 1.8M ins\nLer 1 MB sequencialmente da memória ....... 250,000 ns (250 µs) .......... 3M ins\nRound trip dentro do mesmo datacenter .... 500,000 ns (0.5 ms) .......... 6M ins\nLer 1 MB sequencialmente do SSD- ........ 1,000,000 ns (1 ms) ........... 12M ins\nBusca em disco ......................... 10,000,000 ns (10 ms) ......... 120M ins\nLer 1 MB sequencialmente do disco ...... 20,000,000 ns (20 ms) ......... 240M ins\nEnviar um pacote CA-\u0026gt;Netherlands-\u0026gt;CA .. 150,000,000 ns (150 ms) ........ 1.8B ins\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n \u003cb\u003eLatência\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003eImagem\u003c/b\u003e \u003cb\u003eno\u003c/b\u003e \u003cb\u003eCache\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/cache_latencies_graph.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/cache_latencies_graph.png\"\u003e\n \u003c/a\u003e\n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u003cb\u003eCaches\u003c/b\u003e \u003cb\u003ede\u003c/b\u003e \u003cb\u003eCPU\u003c/b\u003e \u003cb\u003e/\u003c/b\u003e \u003cb\u003eMemória\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=WDIkqP4JbkE\" target=\"_blank\"\u003eCPU Caches and Why You Care - Video\u003c/a\u003e - Scott Meyers \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=OFgxAFdxYAQ\" target=\"_blank\"\u003eA Crash Course in Modern Hardware - Video\u003c/a\u003e - Cliff Click \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://frankdenneman.nl/2016/07/06/introduction-2016-numa-deep-dive-series/\" target=\"_blank\"\u003eNUMA Deep Dive Series\u003c/a\u003e - Frank Denneman \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.aristeia.com/TalkNotes/codedive-CPUCachesHandouts.pdf\" target=\"_blank\"\u003eCPU Caches and Why You Care - Deck\u003c/a\u003e - Scott Meyers \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=MC1EKLQ2Wmg\" target=\"_blank\"\u003eMythbusting Modern Hardware to Gain \u0026#39;Mechanical Sympathy\u0026#39;\u003c/a\u003e - Martin Thompson \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.akkadia.org/drepper/cpumemory.pdf\" target=\"_blank\"\u003eWhat Every Programmer Should Know About Memory\u003c/a\u003e - Ulrich Drepper \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.extremetech.com/extreme/188776-how-l1-and-l2-cpu-caches-work-and-why-theyre-an-essential-part-of-modern-chips\" target=\"_blank\"\u003eHow CPU Caches Work and Why\u003c/a\u003e - Joel Hruska \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.lighterra.com/papers/modernmicroprocessors\" target=\"_blank\"\u003eModern Microprocessors A 90 Minute Guide\u003c/a\u003e - Jason Robert Carey Patterson \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://lwn.net/Articles/252125\" target=\"_blank\"\u003eMemory part 2: CPU caches\u003c/a\u003e - Ulrich Drepper \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.gotw.ca/publications/concurrency-ddj.htm\" target=\"_blank\"\u003eThe Free Lunch Is Over\u003c/a\u003e - Herb Sutter \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://m.youtube.com/watch?feature=youtu.be\u0026amp;v=QBu2Ae8-8LM\" target=\"_blank\"\u003eData Center Computers: Modern Challenges in CPU Design\u003c/a\u003e - Dick Sites \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Wirth%27s_law\" target=\"_blank\"\u003eWirth\u0026#39;s Law\u003c/a\u003e - Wikipedia \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.drdobbs.com/parallel/eliminate-false-sharing/217500206\" target=\"_blank\"\u003eEliminate False Sharing\u003c/a\u003e - Herb Sutter \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://www.ilikebigbits.com/2014_04_21_myth_of_ram_1.html\" target=\"_blank\"\u003eThe Myth Of Ram\u003c/a\u003e - Emil Ernerfeldt \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.infoq.com/presentations/hardware-transactional-memory\" target=\"_blank\"\u003eUnderstanding Transaction Hardware Memory\u003c/a\u003e - Gil Gene \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://youtu.be/jEG4Qyo_4Bc?t=266\" target=\"_blank\"\u003ePerformance Through Cache-Friendliness (4:25-5:48)\u003c/a\u003e - Damian Gryski \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=2EWejmkKlxs\" target=\"_blank\"\u003eGoing Nowhere Faster\u003c/a\u003e - Chandler Carruth \u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n \u003cb\u003eDesign\u003c/b\u003e \u003cb\u003eOrientado\u003c/b\u003e \u003cb\u003ea\u003c/b\u003e \u003cb\u003eDados\u003c/b\u003e\n \u003c/p\u003e\n \n\n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=rX0ItVEVjHc\" target=\"_blank\"\u003eData-Oriented Design and C++\u003c/a\u003e - Mike Acton \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=fHNmRkzxHWs\" target=\"_blank\"\u003eEfficiency with Algorithms, Performance with Data Structures\u003c/a\u003e - Chandler Carruth \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=LrVi9LHP8Bk\" target=\"_blank\"\u003eTaming the performance Beast\u003c/a\u003e - Klaus Iglberger \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://harmful.cat-v.org/software/OO_programming/_pdf/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf\" target=\"_blank\"\u003ePitfalls of OOP\u003c/a\u003e - Tony Albrecht \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.youtube.com/watch?v=YQs6IC-vgmo\" target=\"_blank\"\u003eWhy you should avoid Linked Lists\u003c/a\u003e - Bjarne Stroustrup \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"http://gamesfromwithin.com/data-oriented-design\" target=\"_blank\"\u003eData-Oriented Design (Or Why You Might Be Shooting Yourself in The Foot With OOP)\u003c/a\u003e - Noel \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.quora.com/Was-object-oriented-programming-a-failure\" target=\"_blank\"\u003eWas object-oriented programming a failure?\u003c/a\u003e - Quora \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eSe você não entende os dados, você não entendeu o problema.\u003c/li\u003e\n \n \u003cli\u003eSe você não entendeu o custo para resolver o problema, você não pode discutir sobre o problema.\u003c/li\u003e\n \n \u003cli\u003eSe você não entende o hardware, você não pode discutir sobre os custos de resolver o problema.\u003c/li\u003e\n \n \u003cli\u003eArrays são estruturas de dados com tamanho fixo que não podem ser mudados.\u003c/li\u003e\n \n \u003cli\u003eArrays de tamanhos diferentes são considerados como tipos diferentes.\u003c/li\u003e\n \n \u003cli\u003eMemória é alocada como blocos contíguos.\u003c/li\u003e\n \n \u003cli\u003eGo te da controle sobre localização espacial.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how to declare and iterate over\n// arrays of different types.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare an array of five strings that is initialized\n\t// to its zero value.\n\tvar fruits [5]string\n\tfruits[0] = \"Apple\"\n\tfruits[1] = \"Orange\"\n\tfruits[2] = \"Banana\"\n\tfruits[3] = \"Grape\"\n\tfruits[4] = \"Plum\"\n\n\t// Iterate over the array of strings.\n\tfor i, fruit := range fruits {\n\t\tfmt.Println(i, fruit)\n\t}\n\n\t// Declare an array of 4 integers that is initialized\n\t// with some values.\n\tnumbers := [4]int{10, 20, 30, 40}\n\n\t// Iterate over the array of numbers.\n\tfor i := 0; i \u003c len(numbers); i++ {\n\t\tfmt.Println(i, numbers[i])\n\t}\n}\n","Hash":"M3wQYrY4LVeJJpujAB3Bj6RhBDE="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how arrays of different sizes are\n// not of the same type.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare an array of 5 integers that is initialized\n\t// to its zero value.\n\tvar five [5]int\n\n\t// Declare an array of 4 integers that is initialized\n\t// with some values.\n\tfour := [4]int{10, 20, 30, 40}\n\n\t// Assign one array to the other\n\tfive = four\n\n\t// ./example2.go:21: cannot use four (type [4]int) as type [5]int in assignment\n\n\tfmt.Println(four)\n\tfmt.Println(five)\n}\n","Hash":"iCUwlorg4R1wyH2vlL81vBIs+t8="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how the behavior of the for range and\n// how memory for an array is contiguous.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare an array of 5 strings initialized with values.\n\tfriends := [5]string{\"Annie\", \"Betty\", \"Charley\", \"Doug\", \"Edward\"}\n\n\t// Iterate over the array displaying the value and\n\t// address of each element.\n\tfor i, v := range friends {\n\t\tfmt.Printf(\"Value[%s]\\tAddress[%p] IndexAddr[%p]\\n\", v, \u0026v, \u0026friends[i])\n\t}\n}\n","Hash":"yopDkmW+NnO/BLh1hJ1XHxmy5EA="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program to show how the for range has both value and pointer semantics.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Using the pointer semantic form of the for range.\n\tfriends := [5]string{\"Annie\", \"Betty\", \"Charley\", \"Doug\", \"Edward\"}\n\tfmt.Printf(\"Bfr[%s] : \", friends[1])\n\n\tfor i := range friends {\n\t\tfriends[1] = \"Jack\"\n\n\t\tif i == 1 {\n\t\t\tfmt.Printf(\"Aft[%s]\\n\", friends[1])\n\t\t}\n\t}\n\n\t// Using the value semantic form of the for range.\n\tfriends = [5]string{\"Annie\", \"Betty\", \"Charley\", \"Doug\", \"Edward\"}\n\tfmt.Printf(\"Bfr[%s] : \", friends[1])\n\n\tfor i, v := range friends {\n\t\tfriends[1] = \"Jack\"\n\n\t\tif i == 1 {\n\t\t\tfmt.Printf(\"v[%s]\\n\", v)\n\t\t}\n\t}\n\n\t// Using the value semantic form of the for range but with pointer\n\t// semantic access. DON'T DO THIS.\n\tfriends = [5]string{\"Annie\", \"Betty\", \"Charley\", \"Doug\", \"Edward\"}\n\tfmt.Printf(\"Bfr[%s] : \", friends[1])\n\n\tfor i, v := range \u0026friends {\n\t\tfriends[1] = \"Jack\"\n\n\t\tif i == 1 {\n\t\t\tfmt.Printf(\"v[%s]\\n\", v)\n\t\t}\n\t}\n}\n","Hash":"SxUjCs3iY3iv3zlb7yrlSdZNdIM="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Declare um array com 5 strings com cada elemento inicializado com o seu valor inicial padrão.\n\n\n Declare um segundo array com 5 strings e o inicialize com valores literais para as strings. \n\n\n Atribua o segundo array ao primeiro e mostre o resultado do primeiro array. Imprima o valor da string\n\n\n e o endereço de cada elemento. \n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare an array of 5 strings with each element initialized to its zero value.\n//\n// Declare a second array of 5 strings and initialize this array with literal string\n// values. Assign the second array to the first and display the results of the first array.\n// Display the string value and address of each element.\npackage main\n\n// Add imports.\n\nfunc main() {\n\n\t// Declare an array of 5 strings set to its zero value.\n\n\t// Declare an array of 5 strings and pre-populate it with names.\n\n\t// Assign the populated array to the array of zero values.\n\n\t// Iterate over the first array declared.\n\t// Display the string value and address of each element.\n}\n","Hash":"xhpHHnz5zP1bGB1GKH/72FcBvtI="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Declare an array of 5 strings with each element initialized to its zero value.\n//\n// Declare a second array of 5 strings and initialize this array with literal string\n// values. Assign the second array to the first and display the results of the first array.\n// Display the string value and address of each element.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t// Declare string arrays to hold names.\n\tvar names [5]string\n\n\t// Declare an array pre-populated with friend's names.\n\tfriends := [5]string{\"Joe\", \"Ed\", \"Jim\", \"Erick\", \"Bill\"}\n\n\t// Assign the array of friends to the names array.\n\tnames = friends\n\n\t// Display each string value and address index in names.\n\tfor i, name := range names {\n\t\tfmt.Println(name, \u0026names[i])\n\t}\n}\n","Hash":"C9l3P0ajqI3QHiYA92po7uSzsLU="}]}]} ,"composition-decoupling":{"Title":"Desacoplamento","Description":"A composição vai além dos detalhes mecânicos da incorporação de tipos e é mais do que apenas um paradigma.","Pages":[{"Title":"Desacoplamento","Content":"\n \u003ch2\u003eDesacoplamento\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/training/individual-on-demand/ultimate-go-bundle/\" target=\"_blank\"\u003eAssista ao vídeo\u003c/a\u003e\u003c/li\u003e\n \n \u003cli\u003ePrecisa de Assistência Financeira, Use Nosso \u003ca href=\"https://www.ardanlabs.com/scholarship/\" target=\"_blank\"\u003eFormulário de Bolsa de Estudos\u003c/a\u003e\u003c/li\u003e\n \n \u003c/ul\u003e\n\n \n \u003cp\u003e\n A melhor maneira de aproveitar a incorporação é por meio do padrão de design de \n\n\n composição. É a chave para manter a estabilidade em seu software, permitindo a \n\n\n adaptação às mudanças nos dados e nas transformações que estão por vir.\n \u003c/p\u003e\n \n\n \u003ch2\u003eRevisão de Código\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e1:\u003c/b\u003e Composição de Struct\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e2:\u003c/b\u003e Desacoplamento com Interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e3:\u003c/b\u003e Composição de Interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e4:\u003c/b\u003e Desacoplamento com Composição de Interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e5:\u003c/b\u003e Remover Poluição de Interface\u003c/li\u003e\n \n \u003cli\u003e\u003cb\u003eExemplo\u003c/b\u003e \u003cb\u003e6:\u003c/b\u003e APIs Mais Precisa\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n \u003ch2\u003eMecânicas de Desacoplamento\u003c/h2\u003e\n \n \n \u003cp\u003e\n A ideia é compor tipos maiores a partir de tipos menores e focar na composição \n\n\n de comportamento.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Xenia struct {\n Host string\n Timeout time.Duration\n}\n\nfunc (*Xenia) Pull(d *Data) error {\n switch rand.Intn(10) {\n case 1, 9:\n return io.EOF\n case 5:\n return errors.New(\u0026#34;Error reading data from Xenia\u0026#34;)\n default:\n d.Line = \u0026#34;Data\u0026#34;\n fmt.Println(\u0026#34;In:\u0026#34;, d.Line)\n return nil\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O tipo Xenia representa um sistema do qual você precisa extrair dados. A implementação \n\n\n não é importante. O que é importante é que o método Pull pode ter sucesso, falhar ou não \n\n\n ter nenhum dado para extrair.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Pillar struct {\n Host string\n Timeout time.Duration\n}\n\nfunc (*Pillar) Store(d *Data) error {\n fmt.Println(\u0026#34;Out:\u0026#34;, d.Line)\n return nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n O tipo Pillar representa um sistema no qual você precisa armazenar dados. O que é \n\n\n importante, mais uma vez, é que o método Store pode ter sucesso ou falhar.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Esses dois tipos representam uma camada primitiva de código que fornece o comportamento \n\n\n básico necessário para resolver o problema de negócios de extrair dados do Xenia e \n\n\n armazenar esses dados no Pillar.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Pull(x *Xenia, data []Data) (int, error) {\n for i := range data {\n if err := x.Pull(\u0026amp;data[i]); err != nil {\n return i, err\n }\n }\n\n return len(data), nil\n}\n\nfunc Store(p *Pillar, data []Data) (int, error) {\n for i := range data {\n if err := p.Store(\u0026amp;data[i]); err != nil {\n return i, err\n }\n }\n\n return len(data), nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A próxima camada de código é representada por estas duas funções, Pull e Store. Elas se \n\n\n baseiam na camada primitiva de código ao aceitar uma coleção de valores de dados para \n\n\n extrair ou armazenar nos sistemas correspondentes. Essas funções se concentram nos tipos \n\n\n concretos Xenia e Pillar, uma vez que são os sistemas com os quais o programa precisa \n\n\n trabalhar no momento.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Copy(sys *System, batch int) error {\n data := make([]Data, batch)\n\n for {\n i, err := Pull(\u0026amp;sys.Xenia, data)\n if i \u0026gt; 0 {\n if _, err := Store(\u0026amp;sys.Pillar, data[:i]); err != nil {\n return err\n }\n }\n\n if err != nil {\n return err\n }\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função Copy é construída em cima das funções Pull e Store para mover todos os \n\n\n dados pendentes para cada execução. Se você observar o primeiro parâmetro de Copy, \n\n\n é um tipo chamado System.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype System struct {\n Xenia\n Pillar\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A ideia inicial do tipo System é compor um sistema que sabe como realizar operações \n\n\n de Pull e Store. Neste caso, a composição da capacidade de Pull e Store do Xenia \n\n\n e do Pillar.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n sys := System{\n Xenia: Xenia{\n Host: \u0026#34;localhost:8000\u0026#34;,\n Timeout: time.Second,\n },\n Pillar: Pillar{\n Host: \u0026#34;localhost:9000\u0026#34;,\n Timeout: time.Second,\n },\n }\n\n if err := Copy(\u0026amp;sys, 3); err != io.EOF {\n fmt.Println(err)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Finalmente, a função principal pode ser escrita para construir um Xenia e um Pillar \n\n\n dentro da composição de um System. Em seguida, o System pode ser passado para a \n\n\n função Copy e os dados podem começar a fluir entre os dois sistemas.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Com todo esse código, agora você tem o meu primeiro rascunho de uma solução concreta \n\n\n para um problema concreto.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eDesacoplamento com Interface\u003c/h2\u003e\n \n \n \u003cp\u003e\n O próximo passo é entender o que poderia mudar no programa. Neste caso, o que pode \n\n\n mudar são os próprios sistemas. Hoje pode ser Xenia e Pillar, amanhã pode ser Alice e Bob. \n\n\n Com esse conhecimento, você deseja desacoplar a solução concreta existente dessa mudança. \n\n\n Para fazer isso, você deseja transformar as funções concretas em funções polimórficas.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Pull(p Puller, data []Data) (int, error) {\n for i := range data {\n if err := p.Pull(\u0026amp;data[i]); err != nil {\n return i, err\n }\n }\n\n return len(data), nil\n}\n\nfunc Store(s Storer, data []Data) (int, error) {\n for i := range data {\n if err := s.Store(\u0026amp;data[i]); err != nil {\n return i, err\n }\n }\n\n return len(data), nil\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Atualmente, a função Pull aceita um valor Xenia e a função Store aceita um valor Pillar. No \n\n\n final das contas, não era Xenia e Pillar que eram importantes, mas sim um valor concreto que \n\n\n sabe como Pull e Store. Você pode transformar essas funções concretas em funções polimórficas \n\n\n ao solicitar dados com base no que elas podem fazer, em vez do que são.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype Puller interface {\n Pull(d *Data) error\n}\n\ntype Storer interface {\n Store(d *Data) error\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Essas duas interfaces descrevem o que dados concretos devem fazer, e são esses tipos que \n\n\n são substituídos na declaração das funções Pull e Store. Agora, essas funções são polimórficas. \n\n\n Quando Alice e Bob são declarados e implementados como um Puller e um Storer, eles podem ser \n\n\n passados para as funções.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Você ainda não terminou. A função Copy também precisa ser polimórfica.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Copy(ps PullStorer, batch int) error {\n data := make([]Data, batch)\n\n for {\n i, err := Pull(ps, data)\n if i \u0026gt; 0 {\n if _, err := Store(ps, data[:i]); err != nil {\n return err\n }\n }\n\n if err != nil {\n return err\n }\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função Copy não está mais pedindo um valor System, mas sim qualquer valor concreto \n\n\n que saiba tanto como Pull quanto Store.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype PullStorer interface {\n Puller\n Storer\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A interface PullStorer é declarada por meio do uso de composição. Ela é composta \n\n\n pelas interfaces Puller e Storer. Trabalhe na composição de interfaces maiores a \n\n\n partir das menores.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n Observe como a variável PullStorer agora está sendo passada para as funções Pull e Store.\n\n\n Como isso é possível quando as informações de tipo são diferentes?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003e// func Pull(p Puller, data []Data) (int, error) {\ni, err := Pull(ps, data)\n\n// func Store(s Storer, data []Data) (int, error) {\nif _, err := Store(ps, data[:i]); err != nil {\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Você sempre precisa lembrar que nunca está passando um valor de interface em seu programa, \n\n\n já que eles não existem e não têm valor. Você só pode passar dados concretos. Portanto, \n\n\n os dados concretos armazenados dentro da variável de interface ps é o que está sendo \n\n\n passado para Pull e Store. Não é verdade que o valor concreto armazenado dentro de ps \n\n\n deve saber como realizar as operações de Pull e Store? \n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/comp1.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/comp1.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Uma vez que um System é composto por um Xenia e um Pillar, o System implementa a \n\n\n interface PullStorer. Com essas alterações, você agora pode criar novos tipos \n\n\n concretos que implementam a interface PullStorer.\n\n\n type System1 struct {\n\n\n Xenia\n\n\n Pillar\n\n\n }\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype System2 struct {\n Alice\n Bob\n}\n\ntype System3 struct {\n Xenia\n Bob\n}\n\ntype System4 struct {\n Alice\n Pillar\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Quando você pensa mais sobre isso, declarar diferentes tipos de System para todas as \n\n\n combinações possíveis não é realista. Isso funcionará, mas a dificuldade de manutenção \n\n\n exige uma solução melhor.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eComposição de Interfaces\u003c/h2\u003e\n \n \n \u003cp\u003e\n E se você decidisse compor o seu tipo de sistema concreto a partir de dois tipos de interface?\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003etype System struct {\n Puller\n Storer\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta é uma solução interessante. Isso permitiria que a aplicação injetasse o Puller ou \n\n\n Storer concreto no sistema no momento de inicialização da aplicação.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n sys := System{\n Puller: \u0026amp;Xenia{\n Host: \u0026#34;localhost:8000\u0026#34;,\n Timeout: time.Second,\n },\n Storer: \u0026amp;Pillar{\n Host: \u0026#34;localhost:9000\u0026#34;,\n Timeout: time.Second,\n },\n }\n\n if err := Copy(\u0026amp;sys, 3); err != io.EOF {\n fmt.Println(err)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Este tipo de sistema implementa a interface PullStorer para todas as combinações \n\n\n possíveis de tipos concretos.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/comp2.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/comp2.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Com essa alteração, a aplicação está totalmente desacoplada das mudanças para um \n\n\n novo sistema que pode ser adicionado ao longo do tempo.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eRevisão de Precisão\u003c/h2\u003e\n \n \n \u003cp\u003e\n A próxima pergunta a ser feita é se as funções polimórficas são tão precisas quanto \n\n\n poderiam ser de outra forma. Esta é uma parte do processo de engenharia que não pode \n\n\n ser ignorada. A resposta é não, podem ser feitas duas mudanças.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Copy(sys *System, batch int) error {\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n A função Copy não precisa mais ser polimórfica, uma vez que haverá apenas um tipo \n\n\n System. O tipo de interface PullStorer pode ser removido do programa. Lembre-se \n\n\n de que você moveu o polimorfismo para dentro do tipo quando utilizou a composição \n\n\n com os tipos de interface.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc Copy(p Puller, s Storer, batch int) error {\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Esta é outra alteração que pode ser feita na função Copy. Essa alteração torna \n\n\n a função mais precisa e polimórfica novamente. Agora, a função está solicitando \n\n\n exatamente o que precisa com base no que os dados concretos podem fazer.\n \u003c/p\u003e\n \n\n \u003ca href=\"/tour/eng/static/img/comp3.png\" target=\"_blank\"\u003e\n \u003cimg class=\"codeimg\" src=\"/tour/eng/static/img/comp3.png\"\u003e\n \u003c/a\u003e\n\n \n \u003cp\u003e\n Com essa alteração, o tipo de struct System pode ser removido do programa também.\n \u003c/p\u003e\n \n\n \n \u003cpre class=\"codeblock\"\u003efunc main() {\n x := Xenia{\n Host: \u0026#34;localhost:8000\u0026#34;,\n Timeout: time.Second,\n }\n\n p := Pillar{\n Host: \u0026#34;localhost:9000\u0026#34;,\n Timeout: time.Second,\n }\n\n if err := Copy(\u0026amp;x, \u0026amp;p, 3); err != io.EOF {\n fmt.Println(err)\n }\n}\u003c/pre\u003e\n \n\n \n \u003cp\u003e\n Ao remover os tipos PullStorer e System, o programa se simplifica. A função main \n\n\n pode se concentrar na construção dos valores concretos de Puller e Storer \n\n\n necessários para mover os dados. O sistema de tipos e as APIs ficam mais precisos. \n\n\n Essa ideia de precisão vem de Edsger W. Dijkstra.\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;O propósito da abstração não é ser vago, mas criar um novo nível semântico no qual se pode ser absolutamente preciso.\u0026#34;. - Edsger W. Dijkstra\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eNotas\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003eIsso vai muito além dos mecanismos de incorporação de tipos.\u003c/li\u003e\n \n \u003cli\u003eDeclare tipos e implemente fluxos de trabalho com a composição em mente.\u003c/li\u003e\n \n \u003cli\u003eCompreenda primeiro o problema que você está tentando resolver. Isso significa compreender os dados.\u003c/li\u003e\n \n \u003cli\u003eO objetivo é reduzir e minimizar mudanças em cascata em todo o seu software.\u003c/li\u003e\n \n \u003cli\u003eInterfaces proporcionam a forma mais elevada de composição.\u003c/li\u003e\n \n \u003cli\u003eNão agrupe tipos por um DNA comum, mas por um comportamento comum.\u003c/li\u003e\n \n \u003cli\u003eTodos podem trabalhar juntos quando nos concentramos no que fazemos e não no que somos.\u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n \u003ch2\u003eCitações\u003c/h2\u003e\n \n \n \u003cp\u003e\n \u0026#34;Uma boa API não é apenas fácil de usar, mas também difícil de usar de maneira inadequada.\u0026#34; - JBD\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Você sempre pode incorporar, mas não pode decompor interfaces grandes depois que elas estão em uso. Mantenha as interfaces pequenas.\u0026#34; - JBD\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;Não projete com interfaces, descubra-as.\u0026#34; - Rob Pike\n \u003c/p\u003e\n \n\n \n \u003cp\u003e\n \u0026#34;A duplicação é muito mais barata do que a abstração errada.\u0026#34; - Sandi Metz\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eOrientações de Design\u003c/h2\u003e\n \n \n \u003cp\u003e\n Aprenda sobre as \u003ca href=\"https://github.com/ardanlabs/gotraining/blob/master/topics/go/#interface-and-composition-design\" target=\"_blank\"\u003eorientação de designs\u003c/a\u003e para composição.\n \u003c/p\u003e\n \n\n\n \u003ch2\u003eLeitura Extra\u003c/h2\u003e\n \n \u003cul\u003e\n \n \u003cli\u003e\u003ca href=\"https://programmingisterrible.com/post/176657481103/repeat-yourself-do-more-than-one-thing-and\" target=\"_blank\"\u003eRepeat yourself, do more than one thing, and rewrite everything\u003c/a\u003e - tef \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://golang.org/doc/effective_go.html#embedding\" target=\"_blank\"\u003eEmbedding\u003c/a\u003e \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2014/05/methods-interfaces-and-embedded-types.html\" target=\"_blank\"\u003eMethods, Interfaces and Embedding\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2015/09/composition-with-go.html\" target=\"_blank\"\u003eComposition In Go\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2016/10/reducing-type-hierarchies.html\" target=\"_blank\"\u003eReducing Type Hierarchies\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003cli\u003e\u003ca href=\"https://www.ardanlabs.com/blog/2016/10/avoid-interface-pollution.html\" target=\"_blank\"\u003eAvoid Interface Pollution\u003c/a\u003e - William Kennedy \u003c/li\u003e\n \n \u003c/ul\u003e\n\n\n","Files":[{"Name":"example1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating struct composition.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n// Data is the structure of the data we are copying.\ntype Data struct {\n\tLine string\n}\n\n// =============================================================================\n\n// Xenia is a system we need to pull data from.\ntype Xenia struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Pull knows how to pull data out of Xenia.\nfunc (*Xenia) Pull(d *Data) error {\n\tswitch rand.Intn(10) {\n\tcase 1, 9:\n\t\treturn io.EOF\n\n\tcase 5:\n\t\treturn errors.New(\"error reading data from Xenia\")\n\n\tdefault:\n\t\td.Line = \"Data\"\n\t\tfmt.Println(\"In:\", d.Line)\n\t\treturn nil\n\t}\n}\n\n// Pillar is a system we need to store data into.\ntype Pillar struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Store knows how to store data into Pillar.\nfunc (*Pillar) Store(d *Data) error {\n\tfmt.Println(\"Out:\", d.Line)\n\treturn nil\n}\n\n// =============================================================================\n\n// System wraps Xenia and Pillar together into a single system.\ntype System struct {\n\tXenia\n\tPillar\n}\n\n// =============================================================================\n\n// pull knows how to pull bulks of data from Xenia.\nfunc pull(x *Xenia, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := x.Pull(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// store knows how to store bulks of data into Pillar.\nfunc store(p *Pillar, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := p.Store(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// Copy knows how to pull and store data from the System.\nfunc Copy(sys *System, batch int) error {\n\tdata := make([]Data, batch)\n\n\tfor {\n\t\ti, err := pull(\u0026sys.Xenia, data)\n\t\tif i \u003e 0 {\n\t\t\tif _, err := store(\u0026sys.Pillar, data[:i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// =============================================================================\n\nfunc main() {\n\tsys := System{\n\t\tXenia: Xenia{\n\t\t\tHost: \"localhost:8000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t\tPillar: Pillar{\n\t\t\tHost: \"localhost:9000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t}\n\n\tif err := Copy(\u0026sys, 3); err != io.EOF {\n\t\tfmt.Println(err)\n\t}\n}\n","Hash":"3zMWAO6TA+nQEtLHldV/EgGwWPg="},{"Name":"example2.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating decoupling with interfaces.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n// Data is the structure of the data we are copying.\ntype Data struct {\n\tLine string\n}\n\n// =============================================================================\n\n// Puller declares behavior for pulling data.\ntype Puller interface {\n\tPull(d *Data) error\n}\n\n// Storer declares behavior for storing data.\ntype Storer interface {\n\tStore(d *Data) error\n}\n\n// =============================================================================\n\n// Xenia is a system we need to pull data from.\ntype Xenia struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Pull knows how to pull data out of Xenia.\nfunc (*Xenia) Pull(d *Data) error {\n\tswitch rand.Intn(10) {\n\tcase 1, 9:\n\t\treturn io.EOF\n\n\tcase 5:\n\t\treturn errors.New(\"error reading data from Xenia\")\n\n\tdefault:\n\t\td.Line = \"Data\"\n\t\tfmt.Println(\"In:\", d.Line)\n\t\treturn nil\n\t}\n}\n\n// Pillar is a system we need to store data into.\ntype Pillar struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Store knows how to store data into Pillar.\nfunc (*Pillar) Store(d *Data) error {\n\tfmt.Println(\"Out:\", d.Line)\n\treturn nil\n}\n\n// =============================================================================\n\n// System wraps Xenia and Pillar together into a single system.\ntype System struct {\n\tXenia\n\tPillar\n}\n\n// =============================================================================\n\n// pull knows how to pull bulks of data from any Puller.\nfunc pull(p Puller, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := p.Pull(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// store knows how to store bulks of data from any Storer.\nfunc store(s Storer, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := s.Store(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// Copy knows how to pull and store data from the System.\nfunc Copy(sys *System, batch int) error {\n\tdata := make([]Data, batch)\n\n\tfor {\n\t\ti, err := pull(\u0026sys.Xenia, data)\n\t\tif i \u003e 0 {\n\t\t\tif _, err := store(\u0026sys.Pillar, data[:i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// =============================================================================\n\nfunc main() {\n\tsys := System{\n\t\tXenia: Xenia{\n\t\t\tHost: \"localhost:8000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t\tPillar: Pillar{\n\t\t\tHost: \"localhost:9000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t}\n\n\tif err := Copy(\u0026sys, 3); err != io.EOF {\n\t\tfmt.Println(err)\n\t}\n}\n","Hash":"aUnq+aVJEaKcUUCHcEKiYit70wE="},{"Name":"example3.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating interface composition.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n// Data is the structure of the data we are copying.\ntype Data struct {\n\tLine string\n}\n\n// =============================================================================\n\n// Puller declares behavior for pulling data.\ntype Puller interface {\n\tPull(d *Data) error\n}\n\n// Storer declares behavior for storing data.\ntype Storer interface {\n\tStore(d *Data) error\n}\n\n// PullStorer declares behavior for both pulling and storing.\ntype PullStorer interface {\n\tPuller\n\tStorer\n}\n\n// =============================================================================\n\n// Xenia is a system we need to pull data from.\ntype Xenia struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Pull knows how to pull data out of Xenia.\nfunc (*Xenia) Pull(d *Data) error {\n\tswitch rand.Intn(10) {\n\tcase 1, 9:\n\t\treturn io.EOF\n\n\tcase 5:\n\t\treturn errors.New(\"error reading data from Xenia\")\n\n\tdefault:\n\t\td.Line = \"Data\"\n\t\tfmt.Println(\"In:\", d.Line)\n\t\treturn nil\n\t}\n}\n\n// Pillar is a system we need to store data into.\ntype Pillar struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Store knows how to store data into Pillar.\nfunc (*Pillar) Store(d *Data) error {\n\tfmt.Println(\"Out:\", d.Line)\n\treturn nil\n}\n\n// =============================================================================\n\n// System wraps Xenia and Pillar together into a single system.\ntype System struct {\n\tXenia\n\tPillar\n}\n\n// =============================================================================\n\n// pull knows how to pull bulks of data from any Puller.\nfunc pull(p Puller, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := p.Pull(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// store knows how to store bulks of data from any Storer.\nfunc store(s Storer, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := s.Store(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// Copy knows how to pull and store data from any System.\nfunc Copy(ps PullStorer, batch int) error {\n\tdata := make([]Data, batch)\n\n\tfor {\n\t\ti, err := pull(ps, data)\n\t\tif i \u003e 0 {\n\t\t\tif _, err := store(ps, data[:i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// =============================================================================\n\nfunc main() {\n\tsys := System{\n\t\tXenia: Xenia{\n\t\t\tHost: \"localhost:8000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t\tPillar: Pillar{\n\t\t\tHost: \"localhost:9000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t}\n\n\tif err := Copy(\u0026sys, 3); err != io.EOF {\n\t\tfmt.Println(err)\n\t}\n}\n","Hash":"DOKjIq3KIONIEicYfnXEp5PpyOY="},{"Name":"example4.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating decoupling with interface composition.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n// Data is the structure of the data we are copying.\ntype Data struct {\n\tLine string\n}\n\n// =============================================================================\n\n// Puller declares behavior for pulling data.\ntype Puller interface {\n\tPull(d *Data) error\n}\n\n// Storer declares behavior for storing data.\ntype Storer interface {\n\tStore(d *Data) error\n}\n\n// PullStorer declares behavior for both pulling and storing.\ntype PullStorer interface {\n\tPuller\n\tStorer\n}\n\n// =============================================================================\n\n// Xenia is a system we need to pull data from.\ntype Xenia struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Pull knows how to pull data out of Xenia.\nfunc (*Xenia) Pull(d *Data) error {\n\tswitch rand.Intn(10) {\n\tcase 1, 9:\n\t\treturn io.EOF\n\n\tcase 5:\n\t\treturn errors.New(\"error reading data from Xenia\")\n\n\tdefault:\n\t\td.Line = \"Data\"\n\t\tfmt.Println(\"In:\", d.Line)\n\t\treturn nil\n\t}\n}\n\n// Pillar is a system we need to store data into.\ntype Pillar struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Store knows how to store data into Pillar.\nfunc (*Pillar) Store(d *Data) error {\n\tfmt.Println(\"Out:\", d.Line)\n\treturn nil\n}\n\n// =============================================================================\n\n// System wraps Pullers and Stores together into a single system.\ntype System struct {\n\tPuller\n\tStorer\n}\n\n// =============================================================================\n\n// pull knows how to pull bulks of data from any Puller.\nfunc pull(p Puller, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := p.Pull(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// store knows how to store bulks of data from any Storer.\nfunc store(s Storer, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := s.Store(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// Copy knows how to pull and store data from any System.\nfunc Copy(ps PullStorer, batch int) error {\n\tdata := make([]Data, batch)\n\n\tfor {\n\t\ti, err := pull(ps, data)\n\t\tif i \u003e 0 {\n\t\t\tif _, err := store(ps, data[:i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// =============================================================================\n\nfunc main() {\n\tsys := System{\n\t\tPuller: \u0026Xenia{\n\t\t\tHost: \"localhost:8000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t\tStorer: \u0026Pillar{\n\t\t\tHost: \"localhost:9000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t}\n\n\tif err := Copy(\u0026sys, 3); err != io.EOF {\n\t\tfmt.Println(err)\n\t}\n}\n","Hash":"IVuZhE9B5gqsPmEFZvEYsBxgvRc="},{"Name":"example5.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating removing interface pollution.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n// Data is the structure of the data we are copying.\ntype Data struct {\n\tLine string\n}\n\n// =============================================================================\n\n// Puller declares behavior for pulling data.\ntype Puller interface {\n\tPull(d *Data) error\n}\n\n// Storer declares behavior for storing data.\ntype Storer interface {\n\tStore(d *Data) error\n}\n\n// =============================================================================\n\n// Xenia is a system we need to pull data from.\ntype Xenia struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Pull knows how to pull data out of Xenia.\nfunc (*Xenia) Pull(d *Data) error {\n\tswitch rand.Intn(10) {\n\tcase 1, 9:\n\t\treturn io.EOF\n\n\tcase 5:\n\t\treturn errors.New(\"error reading data from Xenia\")\n\n\tdefault:\n\t\td.Line = \"Data\"\n\t\tfmt.Println(\"In:\", d.Line)\n\t\treturn nil\n\t}\n}\n\n// Pillar is a system we need to store data into.\ntype Pillar struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Store knows how to store data into Pillar.\nfunc (*Pillar) Store(d *Data) error {\n\tfmt.Println(\"Out:\", d.Line)\n\treturn nil\n}\n\n// =============================================================================\n\n// System wraps Pullers and Stores together into a single system.\ntype System struct {\n\tPuller\n\tStorer\n}\n\n// =============================================================================\n\n// pull knows how to pull bulks of data from any Puller.\nfunc pull(p Puller, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := p.Pull(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// store knows how to store bulks of data from any Storer.\nfunc store(s Storer, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := s.Store(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// Copy knows how to pull and store data from any System.\nfunc Copy(sys *System, batch int) error {\n\tdata := make([]Data, batch)\n\n\tfor {\n\t\ti, err := pull(sys, data)\n\t\tif i \u003e 0 {\n\t\t\tif _, err := store(sys, data[:i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// =============================================================================\n\nfunc main() {\n\tsys := System{\n\t\tPuller: \u0026Xenia{\n\t\t\tHost: \"localhost:8000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t\tStorer: \u0026Pillar{\n\t\t\tHost: \"localhost:9000\",\n\t\t\tTimeout: time.Second,\n\t\t},\n\t}\n\n\tif err := Copy(\u0026sys, 3); err != io.EOF {\n\t\tfmt.Println(err)\n\t}\n}\n","Hash":"UswtrL3mrcLRQYrJ8r0m17eOJQA="},{"Name":"example6.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Sample program demonstrating being more precise with API design.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n// Data is the structure of the data we are copying.\ntype Data struct {\n\tLine string\n}\n\n// =============================================================================\n\n// Puller declares behavior for pulling data.\ntype Puller interface {\n\tPull(d *Data) error\n}\n\n// Storer declares behavior for storing data.\ntype Storer interface {\n\tStore(d *Data) error\n}\n\n// =============================================================================\n\n// Xenia is a system we need to pull data from.\ntype Xenia struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Pull knows how to pull data out of Xenia.\nfunc (*Xenia) Pull(d *Data) error {\n\tswitch rand.Intn(10) {\n\tcase 1, 9:\n\t\treturn io.EOF\n\n\tcase 5:\n\t\treturn errors.New(\"error reading data from Xenia\")\n\n\tdefault:\n\t\td.Line = \"Data\"\n\t\tfmt.Println(\"In:\", d.Line)\n\t\treturn nil\n\t}\n}\n\n// Pillar is a system we need to store data into.\ntype Pillar struct {\n\tHost string\n\tTimeout time.Duration\n}\n\n// Store knows how to store data into Pillar.\nfunc (*Pillar) Store(d *Data) error {\n\tfmt.Println(\"Out:\", d.Line)\n\treturn nil\n}\n\n// =============================================================================\n\n// pull knows how to pull bulks of data from any Puller.\nfunc pull(p Puller, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := p.Pull(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// store knows how to store bulks of data from any Storer.\nfunc store(s Storer, data []Data) (int, error) {\n\tfor i := range data {\n\t\tif err := s.Store(\u0026data[i]); err != nil {\n\t\t\treturn i, err\n\t\t}\n\t}\n\n\treturn len(data), nil\n}\n\n// Copy knows how to pull and store data from any System.\nfunc Copy(p Puller, s Storer, batch int) error {\n\tdata := make([]Data, batch)\n\n\tfor {\n\t\ti, err := pull(p, data)\n\t\tif i \u003e 0 {\n\t\t\tif _, err := store(s, data[:i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// =============================================================================\n\nfunc main() {\n\tx := Xenia{\n\t\tHost: \"localhost:8000\",\n\t\tTimeout: time.Second,\n\t}\n\n\tp := Pillar{\n\t\tHost: \"localhost:9000\",\n\t\tTimeout: time.Second,\n\t}\n\n\tif err := Copy(\u0026x, \u0026p, 3); err != io.EOF {\n\t\tfmt.Println(err)\n\t}\n}\n","Hash":"LbmZX7WovpLbUsvAKurO2QuNmi4="}]},{"Title":"Exercícios","Content":"\n \u003ch2\u003eExercícios\u003c/h2\u003e\n \n \n \u003cp\u003e\n Use o template como um ponto de partida para completar os exercícios. Uma possível solução é fornecida.\n \u003c/p\u003e\n \n\n \u003ch2\u003eExercício 1\u003c/h2\u003e\n \n \n \u003cp\u003e\n Usando o template, declare um conjunto de tipos concretos que implementam o conjunto de tipos de interface \n\n\n pré-definidos. Em seguida, crie valores desses tipos e use-os para concluir um conjunto de tarefas pré-definidas.\n \u003c/p\u003e\n \n\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\n\n","Files":[{"Name":"exercise1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Using the template, declare a set of concrete types that implement the set\n// of predefined interface types. Then create values of these types and use\n// them to complete a set of predefined tasks.\npackage main\n\n// Add import(s).\n\n// administrator represents a person or other entity capable of administering\n// hardware and software infrastructure.\ntype administrator interface {\n\tadministrate(system string)\n}\n\n// developer represents a person or other entity capable of writing software.\ntype developer interface {\n\tdevelop(system string)\n}\n\n// =============================================================================\n\n// adminlist represents a group of administrators.\ntype adminlist struct {\n\tlist []administrator\n}\n\n// Enqueue adds an administrator to the adminlist.\nfunc (l *adminlist) Enqueue(a administrator) {\n\tl.list = append(l.list, a)\n}\n\n// Dequeue removes an administrator from the adminlist.\nfunc (l *adminlist) Dequeue() administrator {\n\ta := l.list[0]\n\tl.list = l.list[1:]\n\treturn a\n}\n\n// =============================================================================\n\n// devlist represents a group of developers.\ntype devlist struct {\n\tlist []developer\n}\n\n// Enqueue adds a developer to the devlist.\nfunc (l *devlist) Enqueue(d developer) {\n\tl.list = append(l.list, d)\n}\n\n// Dequeue removes a developer from the devlist.\nfunc (l *devlist) Dequeue() developer {\n\td := l.list[0]\n\tl.list = l.list[1:]\n\treturn d\n}\n\n// =============================================================================\n\n// Declare a concrete type named sysadmin with a name field of type string.\n\n// Declare a method named administrate for the sysadmin type, implementing the\n// administrator interface. administrate should print out the name of the\n// sysadmin, as well as the system they are administering.\n\n// Declare a concrete type named programmer with a name field of type string.\n\n// Declare a method named develop for the programmer type, implementing the\n// developer interface. develop should print out the name of the\n// programmer, as well as the system they are coding.\n\n// Declare a concrete type named company. Declare it as the composition of\n// the administrator and developer interface types.\n\n// =============================================================================\n\nfunc main() {\n\n\t// Create a variable named admins of type adminlist.\n\n\t// Create a variable named devs of type devlist.\n\n\t// Enqueue a new sysadmin onto admins.\n\n\t// Enqueue two new programmers onto devs.\n\n\t// Create a variable named cmp of type company, and initialize it by\n\t// hiring (dequeuing) an administrator from admins and a developer from devs.\n\n\t// Enqueue the company value on both lists since the company implements\n\t// each interface.\n\n\t// A set of tasks for administrators and developers to perform.\n\ttasks := []struct {\n\t\tneedsAdmin bool\n\t\tsystem string\n\t}{\n\t\t{needsAdmin: false, system: \"xenia\"},\n\t\t{needsAdmin: true, system: \"pillar\"},\n\t\t{needsAdmin: false, system: \"omega\"},\n\t}\n\n\t// Iterate over tasks.\n\tfor _, task := range tasks {\n\n\t\t// Check if the task needs an administrator else use a developer.\n\t\tif {\n\n\t\t\t// Dequeue an administrator value from the admins list and\n\t\t\t// call the administrate method.\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Dequeue a developer value from the devs list and\n\t\t// call the develop method.\n\t}\n}\n","Hash":"yBj4Yami3rBJUHVzYmxGceRn7FI="},{"Name":"answer1.go","Content":"// All material is licensed under the Apache License Version 2.0, January 2004\n// http://www.apache.org/licenses/LICENSE-2.0\n\n// Using the template, declare a set of concrete types that implement the set\n// of predefined interface types. Then create values of these types and use\n// them to complete a set of predefined tasks.\npackage main\n\n// Add import(s).\nimport \"fmt\"\n\n// administrator represents a person or other entity capable of administering\n// hardware and software infrastructure.\ntype administrator interface {\n\tadministrate(system string)\n}\n\n// developer represents a person or other entity capable of writing software.\ntype developer interface {\n\tdevelop(system string)\n}\n\n// =============================================================================\n\n// adminlist represents a group of administrators.\ntype adminlist struct {\n\tlist []administrator\n}\n\n// Enqueue adds an administrator to the adminlist.\nfunc (l *adminlist) Enqueue(a administrator) {\n\tl.list = append(l.list, a)\n}\n\n// Dequeue removes an administrator from the adminlist.\nfunc (l *adminlist) Dequeue() administrator {\n\ta := l.list[0]\n\tl.list = l.list[1:]\n\treturn a\n}\n\n// =============================================================================\n\n// devlist represents a group of developers.\ntype devlist struct {\n\tlist []developer\n}\n\n// Enqueue adds a developer to the devlist.\nfunc (l *devlist) Enqueue(d developer) {\n\tl.list = append(l.list, d)\n}\n\n// Dequeue removes a developer from the devlist.\nfunc (l *devlist) Dequeue() developer {\n\td := l.list[0]\n\tl.list = l.list[1:]\n\treturn d\n}\n\n// =============================================================================\n\n// Declare a concrete type named sysadmin with a name field of type string.\ntype sysadmin struct {\n\tname string\n}\n\n// Declare a method named administrate for the sysadmin type, implementing the\n// administrator interface. administrate should print out the name of the\n// sysadmin, as well as the system they are administering.\nfunc (s *sysadmin) administrate(system string) {\n\tfmt.Println(s.name, \"is administering\", system)\n}\n\n// Declare a concrete type named programmer with a name field of type string.\ntype programmer struct {\n\tname string\n}\n\n// Declare a method named develop for the programmer type, implementing the\n// developer interface. develop should print out the name of the\n// programmer, as well as the system they are coding.\nfunc (p *programmer) develop(system string) {\n\tfmt.Println(p.name, \"is developing\", system)\n}\n\n// Declare a concrete type named company. Declare it as the composition of\n// the administrator and developer interface types.\ntype company struct {\n\tadministrator\n\tdeveloper\n}\n\n// =============================================================================\n\nfunc main() {\n\n\t// Create a variable named admins of type adminlist.\n\tvar admins adminlist\n\n\t// Create a variable named devs of type devlist.\n\tvar devs devlist\n\n\t// Enqueue a new sysadmin onto admins.\n\tadmins.Enqueue(\u0026sysadmin{\"John\"})\n\n\t// Enqueue two new programmers onto devs.\n\tdevs.Enqueue(\u0026programmer{\"Mary\"})\n\tdevs.Enqueue(\u0026programmer{\"Steve\"})\n\n\t// Create a variable named cmp of type company, and initialize it by\n\t// hiring (dequeuing) an administrator from admins and a developer from devs.\n\tcmp := company{\n\t\tadministrator: admins.Dequeue(),\n\t\tdeveloper: devs.Dequeue(),\n\t}\n\n\t// Enqueue the company value on both lists since the company implements\n\t// each interface.\n\tadmins.Enqueue(\u0026cmp)\n\tdevs.Enqueue(\u0026cmp)\n\n\t// A set of tasks for administrators and developers to perform.\n\ttasks := []struct {\n\t\tneedsAdmin bool\n\t\tsystem string\n\t}{\n\t\t{needsAdmin: false, system: \"xenia\"},\n\t\t{needsAdmin: true, system: \"pillar\"},\n\t\t{needsAdmin: false, system: \"omega\"},\n\t}\n\n\t// Iterate over tasks.\n\tfor _, task := range tasks {\n\n\t\t// Check if the task needs an administrator else use a developer.\n\t\tif task.needsAdmin {\n\n\t\t\t// Dequeue an administrator value from the admins list and\n\t\t\t// call the administrate method.\n\t\t\tadm := admins.Dequeue()\n\t\t\tadm.administrate(task.system)\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Dequeue a developer value from the devs list and\n\t\t// call the develop method.\n\t\tdev := devs.Dequeue()\n\t\tdev.develop(task.system)\n\t}\n}\n","Hash":"wHVZdN3Bh9/X1DSPXrM4YmRc0ek="}]}]} }