528
SITE OFICIAL: http://golang.org/ LINGUAGEM GO SUBSTITUINDO C++ JAVA E MONO (.NET LINUX) NO SOFTERWARE LIVRE MINHA PRIMEIRA LINGUAGEM DE PROGRAMAÇÃO LÓGICA, TÉCNICAS, ALGORITMOS PARA WEB E VISITE UMA IGREJA EVANGELICA

Linguagem de Programação Go Google Apostila Livro Curso.docx

Embed Size (px)

Citation preview

Page 1: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

LINGUAGEM GOSUBSTITUINDO C++ JAVA E MONO (.NET LINUX) NO SOFTERWARE LIVRE

MINHA PRIMEIRA LINGUAGEM DE PROGRAMAÇÃOLÓGICA, TÉCNICAS, ALGORITMOS PARA WEB E APLICATIVOS

APRENDENDO A PROGRAMARLINGUAGEM APROPRIADA APRENDER PROGRAMAÇÃO

VISITE UMA IGREJA EVANGELICA

Page 2: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Go a Linguagem do Google

Durante muito tempo procurei livros e apostilas em Português sobre linguagem de programação Go, muitas pessoas procuram apreender Go, grande parte do material do site oficial é bom, mas, não é muito explicativo (para ler, são quase termos juridicos), então resolvi traduzir livros gratuitos ou com licenças livres como: An Introduction to Programming in Go de Caleb Doxsey; Learning Go de Miek Gieben e Network Programming with Go de Jan Newmarch (Na Biblioteca https:/ /archive.org/details/opensource podem notar que existem comunidades de tradutores em muitos idiomas, mas, não em Português.). É necessario de uma permição por escrito para publicar uma versão ou derivado, os direitos de cópia (e Impressão) pertencem ao autores dos textos originais, por isso minha tradução é anônima . Grande parte do conteudo foi retirado do livro “THE WAY TO GO” de IVO BALBAERT, muitos tópicos foram suprimidos ou resumidos, este livro se encontra oficialmente e disponivel gratuitamente mais não opensource em (https:/ /archive.org/details/TheWayToGo). Espero que os autores venham a se interessar em publicar seus livros em Portuguesl. Não use este manual para fins comerciais, serve apenas como meio didatico.

O foco dessa publicação é ser um manual para o ensino inicial e intermediário em aplicativos e redes, independente de plataforma (Linux ou Windows) incentivando a produção de programas de códigos aberto, já que Go é uma linguagem bastante facil (mesmo nivel que python) e tambem de códigos aberto.

Professores e alunos participem de uma comunidade de software livre é maneira mais facil e rápida de aprender a programar. Os códigoss livres disponiveis nos sites oficiais ou no sourceforge (onde tudo é open sorce) para Windows, Mac e Linux podem ser usados sob a devida Licença, transcreva estes para programas para linguagem Go, que mesmo sendo estatico tem a portabilidade semelhante ao do Java e Mono (.NET Linux), Explicando: programas podem ser usados em outros S.O's apenas com compilação para plataforma alvo ou usando MinGW.

Esse material traz varios conceitos introdutórios necessario para programação, como Algoritmo e lógica. A popularidade de Go pode extender o uso do Linux no uso pessoal, já que no industrial e em servidores Web é largamente ultilizado, (pouco custo, muita segurança e velocidade).

Exponho agora dois pensamentos que não estão implementados neste momento, mas que deveria ter uma solução livre em GPL v3:

Falta, um programa similar ao Visualg para Go que interprete e execute algoritmos baseado em um idioma nacional (comversor um dicionario de acordo com o idioma falado no pais) para que o ensino de Algoritimos em cursos e o treinamento destes em casa. Para essa atividade a comunidade Linux deve rescrever o códigos do opensource LiteIDE (IDE especifico para Go).

Outra questão é que a estrutura dessa linguagem deve ser usada para reconstrução de uma linguagem de programação C#, (que é de dominio publico) que é muito usado no Windows e linux (Vala).

TRADUTOR: ANÔNIMO IFET

GO É IDEAL PARA USO E COMO PRIMEIRA LINGUAGEM DE PROGRAMAÇÃO

VISITE UMA IGREJA EVANGELICA

Page 3: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

RESUMO DA LINGUAGEM PARA USO DIDATICO:

É UM SOFTWER LIVRE PRODUZIDO PELO GOOGLE ESTATICO (SEM MAQUINA VIRTUAL) VARIOS PLUGINS PARA IDE'S E EDITORES COMPILADOR ON-LINE PARA ESTUDO PROCEDURAL E PARCIALMENTE ORIENTADO A OBJETO CONCORRENTE E PARALELO AUTOMATICAMENTE PORTABILIDADE COMPARADA AO DO JAVA E .NET USO DE 70% MENOS MEMORIA COMPARADO A JAVA PRODUTIVIDADE COMPARADA AO DE UMA LINGUAGEM DE SCRIPT SUPORTE A REDES E PROTOCOLOS DERIVADO DO C COLETA DE LIXO AUTOMATICA SEM ARITMETICA DE PONTEIRO DUCK TIPYNG GRANDE BIBLIOTECA PADÃO E COMPLETA SEM DEPENDENCIAS CIRCULARES DOCUMENTAÇÃO ACOMPANHA O INSTALADOR EXECUÇÃO COMPARADA Á C/C++ COMPILAÇÃO RÁPIDA SIMILAR AO C IDIOMA LEVE COM APENAS 25 PALAVRAS-CHAVE MENOS ESCRITURAÇÃO

Rede Social Acadêmica

http:/ /www.ebah.com.brhttp:/ /passeidireto.com

Principais sites Software e Linux:

www.softwarelivre.gov.brhttp:/ /softwarelivre.orgwww.vivaolinux.com.brhttp:/ /br-linux.orghttp:/ /www.linuxmagazine.com.brhttp:/ /olinux.uol.com.brhttp:/ /www.linuxdescomplicado.com.brhttp:/ /www.linuxbrasil.org.br

VISITE UMA IGREJA EVANGELICA

Page 4: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

PRISM-NSA

PRISM é um programa de vigilância eletrônica altamente secreto mantido pela agência de segurança nacional (NSA) dos Estados Unidos desde 2007. O programa tem como objetivo o monitoramento e a avaliação de mídias eletrônicas, de maneira a possibilitar não apenas a recuperação de informações armazenadas sobre um alvo em específico, mas também a vigilância de comunicações em tempo real. O programa permite a escolha de qualquer cliente das empresas participantes, independentemente de estes serem cidadãos norte-americanos e de estarem ou não nos Estados Unidos. PRISM seria capaz de fornecer à NSA diversos tipos de mídia sobre os alvos escolhidos, como correio eletrônico, conversas por audio e por vídeo, vídeos, fotos, conversações usando voz sobre IP, transferências de arquivos, notificações de login e outros detalhes pertinentes a redes sociais.

Segundo uma apresentação que veio a público, nove das grandes corporações e serviços de Internet participam do programa: Microsoft, Google, Facebook, Yahoo!, Apple, YouTube, AOL, Paltalk e Skype. O jornal The Washington Post apontou ainda que o documento vazado informa que o PRISM é "a principal fonte primária de inteligência usada nos relatórios de análise da NSA".

Software livre surge como alternativa contra espionagem eletrônica

A sabedoria convencional nos diz que precisamos nos precaver contra ladrões e malfeitores.Quando eles eventualmente conseguem seus intentos, precisamos acionar o Estado, através de instituições como Polícia e Justiça, para que possamos fazer valer nossos direitos.

A utilização de softwares livres, ou seja, programas de internet com códigos abertos, que podem ser copiados e modificados por qualquer pessoa, pode ser uma opção para evitar problemas de espionagem como os que foram denunciados recentemente. A avaliação é do diretor-presidente do Serviço Federal de Processamento de Dados (Serpro), Marcos Mazoni.

O mundo do software livre é uma belíssima resposta a tudo isso que está acontecendo no mundo hoje. Se nós trabalhamos com códigos fechados, que não nos permitem saber o que estão fazendo, é muito mais propício a uma decisão desse fornecedor se vai nos espionar ou não. No mundo do software livre, a decisão passa para nós, muda de lado, passa para o mundo do usuário – explica. Mazoni lembra que a implementação do software livre em plataformas de governos sempre teve como foco aumentar a segurança dos dados dos países.

Para debater essas e outras questões, o Serpro promoveu a sexta edição do Congresso Internacional Software Livre e Governo Eletrônico (Consegui), em Brasília. O tema deste ano é Portabilidade, Colaboração e Integração. “São temas muito atuais: estamos trabalhando com a lógica de que o mundo da tecnologia vai ter que suportar mobilidade, rede social, grandes quantidades de informações”, disse Mazoni.

O evento terá 50 oficinas e 150 palestras, com a participação de representantes de diversos países, entre agentes públicos, movimentos sociais, hackativistas, pesquisadores e estudantes para debater

VISITE UMA IGREJA EVANGELICA

Page 5: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

tecnologias que podem ampliar o acesso à informação e agilizar a prestação de serviços públicos.No ano passado, o evento reuniu cerca de 5 mil participantes, e a expectativa é que esse número se

amplie para até 6 mil participantes neste ano. O evento é gratuito e as inscrições podem ser feitas pelo site da organização . Entre as oficinas oferecidas estão edição de músicas e vídeos ou criação de aplicativos móveis e robôs com softwares livres.

O Governo da Nova Zelândia decidiu que não é possível patentear softwares no país, já que a ação prejudica o desenvolvimento de programas de código aberto. Sendo assim, foi aprovado um projeto de lei que exclui programas de computador da lista de itens que podem ser classificados como invenções e, portanto, não são passíveis de patente.

A lei aprovada pelo governo neozelandês cita o crescimento de programas de código livre, gratuitos, e que patentear esse tipo de programa não condiz com o modelo de criação de software opensource. A Nova Zelândia acredita que todos os programas de código-livre são criados utilizando outros programas como base, motivo pelo qual eles não podem ser patenteados. Tudo isso é feito para evitar que desenvolvedores tenham que pagar para os detentores de patentes relacionadas a aplicativos utilizados que, por sua vez, também foram desenvolvidos com outros projetos como base.

De acordo com o governo, diversas pessoas afirmaram que não existe uma verdadeira inovação na criação de softwares, já que eles são sempre desenvolvidos usando outro programa como base. Por causa disso, ceder patentes para um software poderia prejudicar a criação de novidades, já que eles próprios utilizam técnicas já existentes.

A repercussão da consulta aberta pelo Instituto Nacional de Propriedade Industrial do Brasil sobre procedimentos de análise que mexia no campo das patentes de software fez o tema estacionar. Criticado, o INPI diz que espera uma indicação do governo para tocar o projeto.

“Tenho expectativa de que vamos avançar nisso até o fim do ano, mas aguardo um posicionamento do governo, do Ministério do Desenvolvimento”, responde o presidente do INPI, Jorge Ávila, pouco depois de discutir a questão da propriedade intelectual em TICs durante audiência na Câmara dos Deputados.

O INPI não faz segredo de que prefere se alinhar a países como os Estados Unidos e ser mais flexível na concessão de patentes. “No mundo há restrição em alguns campos, menor do que a praticada pelo INPI. Somos, junto com a Índia, um dos países que mais faz restrições a patentes de software”, diz Ávila.

“A solução exige um estudo mais profundo de como é que as patentes se relacionam com o desenvolvimento da economia para fazer mudanças no marco legal. Mas é uma clareza não totalmente pacificada, tanto que até hoje não tivemos consenso para normatizar a diretriz de exames de patentes.”

Linux

Linux é um termo utilizado para se referir sistemas operacionais que utilizem o núcleo Linux. O núcleo Linux foi desenvolvido pelo programador finlandês Linus Torvalds, inspirado no sistema Minix. O seu código fonte está disponível sob a licença GPL (versão 2) para que qualquer pessoa o possa utilizar, estudar, modificar e distribuir livremente de acordo com os termos da licença.

Inicialmente desenvolvido e utilizado por grupos de entusiastas em computadores pessoais, os sistemas operacionais com núcleo Linux passaram a ter a colaboração de grandes empresas como IBM, Sun Microsystems, Hewlett-Packard (HP), Red Hat, Novell, Oracle, Google, Mandriva e Canonical (criadora do Ubuntu).

Apoiado por pacotes igualmente estáveis e cada vez mais versáteis de softwares livres para escritório (Libre Office, por exemplo) ou de uso geral (projeto GNU) e por programas para micro e pequenas empresas que na maioria dos casos em nada ficam a dever aos seus concorrentes proprietários, e interfaces gráficas cada vez mais amigáveis como o KDE e o GNOME, o núcleo Linux, conhecido por sua estabilidade e robustez, tem gradualmente caído no domínio popular, encontrando-se cada vez mais presente nos computadores de uso pessoal atuais. Mas já há muito que o Linux destaca-se como o núcleo preferido em servidores de grandes porte, encontrando-se quase sempre presente nos mainframes de grandes empresas e até mesmo no computador mais rápido do mundo, o Tianhe-2, chinês (lista mundial TOP500 dos supercomputadores).

GNU General Public License

GNU General Public License (Licença Pública Geral), GNU GPL ou simplesmente GPL, é a designação

VISITE UMA IGREJA EVANGELICA

Page 6: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

da licença para software livre idealizada por Richard Matthew Stallman em 1989, no âmbito do projeto GNU da Free Software Foundation (FSF). A GPL é a licença com maior utilização por parte de projetos de software livre, em grande parte devido à sua adoção para o projeto GNU e o sistema operacional GNU/Linux. O software utilizado para administrar o conteúdo da Wikipédia é coberto por esta licença, na sua versão 2.0 ou superiores. Em termos gerais, a GPL baseia-se em 4 liberdades:

1. A liberdade de executar o programa, para qualquer propósito (liberdade nº 0)2. A liberdade de estudar como o programa funciona e adaptá-lo para as suas necessidades (liberdade nº 1).

O acesso ao código-fonte é um pré-requisito para esta liberdade.3. A liberdade de redistribuir cópias de modo que você possa ajudar ao seu próximo (liberdade nº 2).4. A liberdade de aperfeiçoar o programa, e liberar os seus aperfeiçoamentos, de modo que toda a

comunidade se beneficie deles (liberdade nº 3). O acesso ao código-fonte é um pré-requisito para esta liberdade.

Com a garantia destas liberdades, a GPL permite que os programas sejam distribuídos e reaproveitados, mantendo, porém, os direitos do autor por forma a não permitir que essa informação seja usada de uma maneira que limite as liberdades originais. A licença não permite, por exemplo, que o código seja apoderado por outra pessoa, ou que sejam impostos sobre ele restrições que impeçam que seja distribuído da mesma maneira que foi adquirido.

A GPL está redigida em inglês e atualmente nenhuma tradução é aceita como válida pela Free Software Foundation, com o argumento de que há o risco de introdução de erros de tradução que poderiam deturpar o sentido da licença. Deste modo, qualquer tradução da GPL é não-oficial e meramente informativa, mantendo-se a obrigatoriedade de distribuir o texto oficial em inglês com os programas.

A licença GPL foi originalmente publicada em Janeiro de 1989. No entanto, passado pouco tempo, ficou claro que o texto da licença comportava vários problemas, pelo que em Junho de 1991 foi publicada a GPL versão 2, sendo ao mesmo tempo introduzida uma nova licença LGPL. Em 2005, Stallman anunciou que estava a preparar uma nova versão da licença em conjunto com Eben Moglen. Essa nova versão, foi chamada de GPLv3 e o primeiro esboço foi publicado em 16 de Janeiro de 2006, sendo a versão estreitol lançada em 29 de Junho de 2007.

Em 2001, Steve Ballmer, da Microsoft, se referiu ao Linux como "um câncer que se junta à propriedade intelectual e contamina tudo que toca". Porém, críticos alegam contra Microsoft que o verdadeiro motivo para a empresa atacar a GPL é o fato desta licença "resistir às tentativas dos direitos de propriedade intelectual convencionais se estenderem sobre todas as criações e inovações da área". Em resposta aos ataques da Microsoft à GPL, muitos desenvolvedores e defensores de Softwares Livres fizeram uma proclamação conjunta a favor da licença. Contudo, em julho de 2009, a própria Microsoft incluiu um bloco de aproximadamente 20.000 linhas, sob licença GPL, ao conjunto de drivers do Linux. O código do Hyper-V que era parte do código submetido usou componentes opensource licenciados sob a GPL. Era originalmente linkado estaticamente a partes de binários pertencentes à proprietários de direitos autorais, que são inadmissíveis em um software licenciado através da GPL.

A GPL tem sido descrita como “viral” por muitos críticos porque ela apenas permite programas inteiros, o que significa que não é permitido aos programadores linkar seu projeto a bibliotecas sob licenças incompatíveis à GPL. O efeito “viral” ocorre nos casos em que os códigos não podem ser combinados a menos que a licença de um deles sofra alguma alteração. Embora teoricamente qualquer uma das licenças possa ser mudada, no contexto “viral” isso é mais difícil de ocorrer com a GPL (porque o software pode ter muitos contribuintes, dos quais alguns geralmente se recusam permitir mudanças nos termos de licença), ao passo que a licença dos outros softwares pode ser mudada. De acordo com Richard Stallman, a imagem de um “vírus” não é apenas ofensiva, como também errônea: Software sob licença GPL nunca ataca ou infecta outro software. Ela se comporta mais como uma planta. Se um pedaço é aproveitado como enxerto em outro lugar, ela cresce lá também.

Em um mercado grande, códigos sob licença GPL tem preço praticamente nulo, pois cada usuário tem igual direito de revendê-lo. Isso pode inibir o interesse no seu uso ao comprometer os interesses econômicos do desenvolvedor. A Microsoft, por exemplo, inclui termos anti-GPL ao disponibilizar seus códigos. Porém essa crítica é rebatida na observação de que empresas que focam seus negócios em software livre, como a Red Hat e a IBM, trabalham na venda de serviços agregados como suporte e desenvolvimento de novas funcionalidades, ao invés da venda do software.

História

O núcleo (ou Kernel) Linux foi, originalmente, escrito por Linus Torvalds do Departamento de Ciência da Computação da Universidade de Helsinki, Finlândia, com a ajuda de vários programadores voluntários através da Usenet (uma espécie de sistema de listas de discussão existente desde os primórdios da

VISITE UMA IGREJA EVANGELICA

Page 7: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Internet).Linus Torvalds começou o desenvolvimento do núcleo como um projeto particular, inspirado pelo seu

interesse no Minix, um pequeno sistema UNIX desenvolvido por Andrew S. Tanenbaum. Ele limitou-se a criar, nas suas próprias palavras, "um Minix melhor que o Minix" ("a better Minix than Minix"). E depois de algum tempo de trabalho no projeto, sozinho, enviou uma mensagem para comp.os.minix.

Curiosamente, o nome Linux foi criado por Ari Lemmke, administrador do site ftp.funet.fi que deu esse nome ao diretório FTP onde o núcleo Linux estava inicialmente disponível. Linus inicialmente tinha-o batizado como "Freax".

No dia 5 de outubro de 1991 Linus Torvalds anunciou a primeira versão "oficial" do núcleo Linux, versão 0.02. Desde então muitos programadores têm respondido ao seu chamado, e têm ajudado a fazer do Linux o sistema operacional que é hoje. No início era utilizado por programadores ou só por quem tinha conhecimentos, usavam linhas de comando. Hoje isso mudou, existem diversas empresas que criam os ambientes gráficos, as distribuições cada vez mais amigáveis de forma que uma pessoa com poucos conhecimentos consegue usar o Linux. Hoje o Linux é um sistema estável e consegue reconhecer muitos periféricos sem a necessidade de se instalar os drivers de som, vídeo, modem, rede, entre outros.

Arquitetura

O Linux é um núcleo monolítico: as funções do núcleo (escalonamento de processos, gerenciamento de memória, operações de entrada/saída, acesso ao sistema de arquivos) são executadas no espaço de núcleo. Uma característica do núcleo Linux é que algumas das funções (drivers de dispositivos, suporte à rede, sistema de arquivos, por exemplo) podem ser compiladas e executadas como módulos (em inglês: LKM - loadable kernel modules), que são bibliotecas compiladas separadamente da parte principal do núcleo e podem ser carregadas e descarregadas após o núcleo estar em execução.

Embora Linus Torvalds não tivesse como objetivo inicial tornar o Linux um sistema portátil, ele evoluiu nessa direção. Linux é hoje um dos núcleos de sistemas operativos mais portáteis, correndo em sistemas desde o iPaq (um computador portátil) até o IBM S/390 (um denso e altamente custoso mainframe).

Os esforços de Linus foram também dirigidos a um diferente tipo de portabilidade. Portabilidade, de acordo com Linus, era a habilidade de facilmente compilar aplicações de uma variedade de código fonte no seu sistema; consequentemente, o Linux originalmente tornou-se popular em parte devido ao esforço para que os códigos-fonte GPL ou outros favoritos de todos corressem em Linux.

O Linux hoje funciona em dezenas de plataformas, desde mainframes até um relógio de pulso, passando por várias arquiteturas: x86 (Intel, AMD), x86-64 (Intel EM64T, AMD64), ARM, PowerPC, Alpha, SPARC e etc., com grande penetração também em sistemas embarcados, como handhelds, PVR, console de vídeo e jogos, celulares, TVs e centros multimídia, entre outros.

Termos de licenciamento

Inicialmente, Torvalds lançou o Linux sob uma licença de software que proibia qualquer uso comercial. Isso foi mudado de imediato para a GNU General Public License. Essa licença permite a distribuição e mesmo a venda de versões possivelmente modificadas do Linux, mas requer que todas as cópias sejam lançadas dentro da mesma licença e acompanhadas do código fonte.

Apesar de alguns dos programadores que contribuem para o núcleo permitirem que o seu código seja licenciado com GPL versão 2 ou posterior, grande parte do código (incluído as contribuições de Torvalds) menciona apenas a GPL versão 2. Isto faz com que o núcleo como um todo esteja sob a versão 2 exclusivamente, não sendo de prever sua adoção da nova GPLv3.

Desde o começo, o núcleo Linux incluía um sistema básico para chamadas do sistema e acesso aos dispositivos do computador. O núcleo de um sistema operativo define entre várias operações, o gerenciamento da memória, de processos, dos dispositivos físicos no computador e é uma parte essencial de qualquer sistema operacional utilizável, contudo para um sistema operacional adquirir funcionalidade são necessários também vários outros aplicativos que determinam funções específicas que aquele sistema será capaz de desenvolver, os aplicativos existentes em um sistema operacional com a única exceção do núcleo são determinados pelo usuário do computador, como por exemplo: interpretadores de comandos, gerenciadores de janelas, que oferecem respectivamente uma interface para o usuário do computador, CLI ou GUI, e outros aplicativos como editores de texto, editores de imagem, tocadores de som, e, mas não necessariamente, compiladores.

A maioria dos sistemas inclui ferramentas e utilitários baseados no BSD e tipicamente usam XFree86 ou X.Org para oferecer a funcionalidade do sistemas de janelas X — interface gráfica. Assim como também oferecem ferramentas desenvolvidas pelo projeto GNU.

VISITE UMA IGREJA EVANGELICA

Page 8: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

No momento do desenvolvimento do Linux, vários aplicativos já vinham sendo reunidos pelo Projeto GNU da Free Software Foundation (‘Fundação Software Livre’), que embarcara em um subprojeto que ainda continua para obter um núcleo, o GNU Hurd. Porém devido a várias complicações o projeto GNU e demora em desenvolver o Hurd, Stallman acabou adotando o núcleo Linux como base para distribuir os programas do projeto GNU, não obstante diversas pessoas e instituições tiveram a mesma ideia e assim várias distribuições começaram a surgir baseadas no núcleo desenvolvido inicialmente por Linus.

Distribuições

Atualmente, um Sistema Operacional Linux ou GNU/Linux completo é uma coleção de software livre (e por vezes não-livres) criados por indivíduos, grupos e organizações de todo o mundo, incluindo o núcleo Linux. Companhias como a Red Hat, a SUSE, a Mandriva e a Canonical (desenvolvedora do Ubuntu Linux), bem como projetos de comunidades como o Debian ou o Gentoo, compilam o software e fornecem um sistema completo, pronto para instalação e uso. Patrick Volkerding também fornece uma distribuição Linux, o Slackware.

As distribuições do Linux ou GNU/Linux começaram a receber uma popularidade limitada desde a segunda metade dos anos 90, como uma alternativa livre para os sistemas operacionais Microsoft Windows e Mac OS, principalmente por parte de pessoas acostumadas com o Unix na escola e no trabalho. O sistema tornou-se popular no mercado de Desktops e servidores, principalmente para a Web e servidores de bancos de dados.

No decorrer do tempo, várias distribuições surgiram e desapareceram, cada qual com sua característica. Algumas distribuições são maiores outras menores, dependendo do número de aplicações e sua estreitolidade. Algumas distribuições de tamanhos menores cabem num disquete com 1,44 MB, outras precisam de vários CDs, existindo até algumas versões em DVD.

Todas elas tem o seu público e sua estreitolidade, as pequenas (que ocupam poucos disquetes) são usadas para recuperação de sistemas danificados ou em monitoramento de redes de computadores.

Dentre as maiores, distribuídas em CDs, podem-se citar: Slackware, Debian, Suse, e Conectiva. Cada distribuição é, em tese, um sistema operacional independente, de modo que os programas compilados para uma distribuição podem não rodar em outra, embora usem o mesmo núcleo (o Linux propriamente dito). A distribuição Conectiva Linux, por exemplo, tinha as suas aplicações traduzidas em português, o que facilitou que usuários que falam a Língua Portuguesa tenham aderido melhor a esta distribuição. Hoje está distribuição foi incorporada à Mandrake, o que resultou na Mandriva.

Existem distribuições com ferramentas para configuração que facilitam a administração do sistema.As principais diferenças entre as distribuições estão nos seus sistemas de pacotes, nas estruturas dos

diretórios e na sua biblioteca básica. Por mais que a estrutura dos diretórios siga o mesmo padrão, o FSSTND é um padrão muito relaxado, principalmente em arquivos onde as configurações são diferentes entre as distribuições. Então normalmente todos seguem o padrão FHS (File Hierarchy System), que é o padrão mais novo. Vale lembrar, entretanto, que qualquer aplicativo ou driver desenvolvido para Linux pode ser compilado em qualquer distribuição que vai funcionar da mesma maneira.

Quanto à biblioteca, é usada a Biblioteca libc, contendo funções básicas para o sistema Operacional Linux. O problema está quando do lançamento de uma nova versão da Biblioteca libc, algumas das distribuições colocam logo a nova versão, enquanto outras aguardam um pouco. Por isso, alguns programas funcionam numa distribuição e noutras não.

Existe um movimento LSB (Linux Standard Base) que proporciona uma maior padronização. Auxilia principalmente vendedores de software que não liberam para distribuição do código fonte, sem tirar características das distribuições. O sistemas de pacotes não é padronizado.

Ubuntu, ArchLinux, Debian, Fedora, Mandriva, Opensuse, PCLinuxOS, Puppy, Sabayon, Slackware e Mint, são algumas das distribuições mais utilizadas atualmente. De entre as distribuições consideradas mais difíceis de gerir (por preferirem assegurar a estabilidade tecnológica em detrimento da interface de utilizador), destacam-se a Debian, Gentoo e Slackware.

Um programa, assim como toda obra produzida atualmente, seja ela literária, artística ou tecnológica, possui um autor. Os Direitos sobre a ideia ou originalidade da obra do autor, que incluem essencialmente distribuição, reprodução e uso é feito no caso de um programa através de sua licença.

Existem dois movimentos que regem o licenciamento de programas no mundo livre, os programas de código aberto e os programas livres. Os dois representados respectivamente pela OSI e pela FSF oferecem licenças para produção de software, sendo seus maiores representantes a licença BSD e a GPL.

O Linux oferece muitos aplicativos de opensource, contudo nem todos podem ser considerados programas livres, dependendo exclusivamente sob qual licença estes programas são distribuídos. Os programas distribuídos sob tais licenças possuem as mais diversas funcionalidades, como desktops, escritório, edição de imagem e inclusive de outros sistemas operacionais.

Também existem organizações inclusive no mundo livre como a organização Linux Simples para o

VISITE UMA IGREJA EVANGELICA

Page 9: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Usuário Estreitol (SEUL) que tem como objetivo adotar a maior gama possível de aplicativos de alta qualidade produzidos sobre a GPL. É um projeto voluntário que atualmente se foca no aprendizado de Linux, seu uso na ciência e em documentos de advocacia, bem como gerenciar e coordenar projetos de desenvolvimento de aplicativos.

Usando Aplicativos Windows no Linux

Wine (acrónimo recursivo para WINE Is Not an Emulator, isto é, WINE Não é um Emulador, em tradução livre) é um emulador para sistemas operativos UNIX que tem como objetivo a implementação da API do Microsoft Windows. Desta forma, em teoria, o Wine permite a execução de aplicações desenvolvidas para ambiente Windows nativamente noutros sistemas operativos. Wine, traduzido literalmente do inglês para o português, significa vinho, o que levou à escolha de uma taça de vinho como logotipo do Wine.

Por reimplementar as bibliotecas do Windows o Wine não é um emulador, não fazendo qualquer emulação para executar software para Windows. A implementação da API do Windows faz-se através da utilização de APIs e funções específicas de ambientes UNIX, sendo apenas necessária a implementação adicional de um carregador de aplicativos no formato PE, capaz de os converter para o formato ELF em run-time.

O WINE atua, então, algo como um "tradutor": toda vez que ocorre uma chamada para a função desenha Cubo que estava implementada no Directx.dll por exemplo, o Wine traduz está chamada para uma de suas próprias bibliotecas em que alguém escreveu uma função similar para realizar exatamente o mesmo, desenhar um cubo na tela. Por isto às vezes os jogos que rodam em cima do Wine geram erros, pois executam chamadas a funções que o Wine não sabe como interpretar, isto é, chamam bibliotecas ou funções muito novas que os desenvolvedores do Wine ainda não implementaram. No entanto, o Wine permite a utilização de bibliotecas nativas, apesar de, dado o fato de ser uma aplicação em user-mode num sistema operativo UNIX, nem todas funcionarem. Por exemplo, a utilização do Directx da Microsoft é uma impossibilidade técnica (e legal).

O Wine ainda disponibiliza a sua própria biblioteca (Winelib) por forma a que o código-fonte dos programas concebidos para Windows possa ser compilado no ambiente UNIX. Assim, programas desenvolvidos para Windows podem ser portados para plataformas UNIX e, inclusivamente, para outras arquiteturas, desde que exista o código fonte. No entanto, os programas compilados com Winelib precisam de ser executados sempre no Wine e, em particular, sempre na mesma versão.

O nome Wine era inicialmente um acrônimo de Windows Emulator.1 Seu significado mais tarde deslocado para o Acrônimo recursivo, Wine Is Not an Emulator.2 Embora o nome às vezes aparece sob as formas WINE e wine, os desenvolvedores decidiram padronizar para Wine.3

O Wine foi também um dos alfas mais longos de todos. Levou cerca de 10 anos desde o início de seu desenvolvimento em 1993, por Bob Amstadt e Eric Youngdale, até a versão 1.0, lançada em junho de 2008.

O projeto está atualmente na versão 1.7.10, desde 3 de janeiro de 2014. Já executa muitos programas, entre eles Adobe Photoshop, DreaMule, Filezilla, Macromedia Flash, Microsoft Office, Corel Draw (até versão 8), Microsoft Internet Explorer, mGOC, uTorrent, Ares Galaxy, Shareaza, Firefox (versão do Windows) e Winamp. O projeto também é capaz de executar diversos e conhecidos jogos como Need for Speed Underground, Warcraft III, StarCraft, Max Payne, Max Payne 2: The Fall of Max Payne, Counter Strike, Half-Life, Half-life², World of Warcraft, Resident Evil 4, Tetris Zone, entre outros.

Sobre o símbolo

VISITE UMA IGREJA EVANGELICA

Page 10: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Tux - símbolo do software foi escolhido pelo seu criador (Linus Torvalds), que um dia estava no zoológico e foi surpreendido pela mordida de um pinguim. Fato curioso e discutido até hoje.

Em 1996, muitos integrantes da lista de discussão "Linux-Kernel" estavam discutindo sobre a criação de um logotipo ou de um mascote que representasse o Linux. Muitas das sugestões eram paródias ao logotipo de um sistema operacional concorrente e muito conhecido (Windows). Outros eram monstros ou animais agressivos. Linus Torvalds acabou entrando nesse debate ao afirmar em uma mensagem que gostava muito de pinguins. Isso foi o suficiente para dar fim à discussão.

Depois disso, várias tentativas foram feitas numa espécie de concurso para que a imagem de um pinguim servisse aos propósitos do Linux, até que alguém sugeriu a figura de um "pinguim sustentando o mundo". Em resposta, Linus Torvalds declarou que achava interessante que esse pinguim tivesse uma imagem simples: um pinguim "gordinho" e com expressão de satisfeito, como se tivesse acabado de comer uma porção de peixes. Torvalds também não achava atraente a ideia de algo agressivo, mas sim a ideia de um pinguim simpático, do tipo em que as crianças perguntam "mamãe, posso ter um desses também?". Ainda, Torvalds também frisou que trabalhando dessa forma, as pessoas poderiam criar várias modificações desse pinguim. Isso realmente acontece.

Quando questionado sobre o porquê de pinguins, Linus Torvalds respondeu que não havia uma razão em especial, mas os achava engraçados e até citou que foi bicado por um "pinguim assassino" na Austrália e ficou impressionado como a bicada de um animal aparentemente tão inofensivo podia ser tão dolorosa.

Ubuntu

Ubuntu é um sistema operacional de código aberto, construído a partir do núcleo Linux, baseado no Debian. É patrocinado pela Canonical Ltda.

O Ubuntu diferencia-se do Debian por ter versões lançadas semestralmente, por disponibilizar suporte técnico nos 9 meses seguintes ao lançamento de cada versão (as versões LTS – Long Term Support – para desktop recebem 5 anos de suporte, e para servidor recebem 5 anos de suporte), e pela filosofia em torno de sua concepção. A proposta do Ubuntu é oferecer um sistema que qualquer pessoa possa utilizar sem dificuldades, independentemente de nacionalidade, nível de conhecimento ou limitações físicas. O sistema deve ser constituído principalmente por software livre. Deve também ser isento de qualquer taxa.

Os fãs do Ubuntu são conhecidos como "ubuntistas", "ubunteiros" ou "ubunteros". Atualmente, a página do Ubuntu no Distrowatch é segunda mais acessada (com base anual).

Em 8 de julho de 2005, Mark Shuttleworth e a Canonical Ltda. anunciaram a criação da Fundação Ubuntu e providenciaram um suporte inicial de US$ 10 milhões. A estreitolidade da fundação é garantir apoio e desenvolvimento a todas as versões posteriores à 5.10.

O nome "Ubuntu" AFI:[u'buntu] deriva do conceito sul africano de mesmo nome, diretamente traduzido como "humanidade com os outros" ou "sou o que sou pelo que nós somos".

Esse nome busca passar a ideologia do projeto, baseada nas liberdades do software livre e no trabalho comunitário de desenvolvimento. O sistema é muito comumente chamado "Ubuntu Linux", porém, oficialmente a Canonical, desenvolvedora do sistema, usa apenas o nome "Ubuntu", uma vez que o sistema ao ser portado para outros núcleos livres para além do Linux recebe outros nomes (por exemplo, o Ubuntu

VISITE UMA IGREJA EVANGELICA

Page 11: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

implementado sobre o Open Solaris recebe o nome de "Nexenta") - ao contrário do Debian, por exemplo, que recebe este nome independentemente do núcleo usado.

Características

Novas versões do Ubuntu são lançadas duas vezes ao ano, uma no mês de Abril e outra no mês de Outubro.

Um dos focos principais é a usabilidade, incluindo o uso da ferramenta sudo para tarefas administrativas (similar ao Mac OS X) e a oferta de uma gama de recursos completa a partir de uma instalação padrão

Acessibilidade e internacionalização, permitindo a utilização do sistema pelo maior número de pessoas possível. A partir da versão 5.04, a codificação de caracteres padrão é o UTF-8 (permitindo a utilização de caracteres não utilizados no alfabeto latino). O projeto visa também a oferecer suporte técnico nos idiomas de seus usuários

Além das ferramentas de sistema padrão e outros aplicativos menores, o Ubuntu é oferecido com diversos programas pré-instalados que atendem às funcionalidades básicas, entre os quais estão a suíte de aplicativos Libre Office e o navegador de internet Firefox. Programas para visualizar conteúdos multimídia, clientes de e-mail e jogos simples completam o sistema básico

O Ubuntu possui uma forte ligação com a comunidade Debian, contribuindo direto ou indiretamente com qualquer modificação nos códigos fonte, ao invés de apenas anunciar essas mudanças em uma data posterior. Muitos programadores do Ubuntu mantêm pacotes chave do próprio Debian

Todas as versões do Ubuntu são disponibilizadas sem custo algum. O visual padrão até a versão 5.10 e na versão 9.10 caracteriza-se pela utilização de tons castanhos;

entre as versões 6.06 (Dapper Drake) e 9.04 (Jaunty Jackalope), no entanto, passou-se a usar um padrão de cores mais próximo do laranja. A versão 10.04 passou a adotar um padrão de cores mais diversificado

A gestão de instalação de software é realizada pelo APT, Central de Programas ou pelo Synaptic O Ubuntu cabe em um único CD e é oferecido como um Live CD que pode ser utilizado para uma

instalação permanente. O Live CD é utilizado por muitos usuários a fim de testar a compatibilidade de hardware antes de instalar o sistema

Qualquer versão até a 12.04 ocupa apenas um CD (até 700 MB); a partir da versão 12.10, será necessário um DVD ou um pen drive, pelo fato da nova versão ultrapassar o limite de 700 MB. A atualização e instalação de mais programas poderá ser realizada via Internet, num processo fácil e em ambiente gráfico.

Para quem pretende experimentar o Ubuntu sem o instalar no disco rígido, o sistema funciona em um Live CD diretamente do CD, sem necessidade de ser instalado. Pode-se instalá-lo a partir de um pen drive também. Estes modos são mais lentos e destinam-se essencialmente a proporcionar um primeiro contato com o Ubuntu, seus programas incluídos e saber quais programas podem ser eventualmente instalados; além de ser útil para manutenção de hardware. A partir da versão 6.06, este disco pode ser utilizado para se instalar definitivamente no computador.

Requisitos de sistema

A versão desktop do Ubuntu atualmente suporta as arquiteturas Intel x86 e AMD64. Suporte não-oficial é disponibilizado para PowerPC, IA-64 (Itanium) e PlayStation 3 (contudo observe que a Sony removeu oficialmente o suporte para o Linux no PS3 com o firmware3.21, lançado em 1º de abril de 2010). Uma GPU suportada é requerida para habilitar efeitos visuais.

Requisitos mínimos Servidor Desktop

Processor (x86) com o conjunto de instruções i686 300 MHz 700 MHz

Memória RAM 128 MiB 512 MiB

Disco rígido (espaço livre) 1 GB 5 GB

Resolução do monitor 640×480 1024×768

Uma nova versão do Ubuntu é lançada semestralmente, e cada lançamento tem um nome de código e um número de versão. O número de versão é baseado no ano e no mês de lançamento. Por exemplo o Ubuntu 4.10 foi lançado em outubro de 2004, na data: mês 10, ano 2004. Abaixo está uma lista dos lançamentos anteriores e os lançamentos planejados. A partir da versão 13.04 em diante, o suporte em versões não-LTS foi alterado de 18 para 9 meses.

VISITE UMA IGREJA EVANGELICA

Page 12: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Projetos derivados Além do Ubuntu, existem algumas versões derivadas que são oficialmente reconhecidas:

Kubuntu, versão do Ubuntu que utiliza o ambiente gráfico KDE Xubuntu, Ubuntu para computadores menos potentes, utilizando o ambiente gráfico Xfce Gobuntu, Ubuntu somente com software livre, utilizando o ambiente gráfico GNOME Fluxbuntu, Ubuntu somente com software livre, utilizando o ambiente gráfico FluxBox Ubuntu Studio, para edição e criação de conteúdo multimídia Edubuntu, Ubuntu desenvolvido para o uso em escolas Lubuntu, distro com interface gráfica LXDE voltada para computadores atrás e/ou pouco potentes

Dentre as versões não-oficiais (derivadas) destacam-se:

Linux Mint Ultimate Edition Super OS elementary OS

Além desses, Mark Shuttleworth aprovou a criação de uma distribuição que usa exclusivamente software livre aprovado pela FSF, a gNewSense. Estes projetos estão ligados oficialmente ao Ubuntu, com lançamentos simultâneos e compatibilidade de pacotes, obtidos dos mesmos repositórios oficiais. Espalhou-se o boato que o Google estava desenvolvendo um derivado do Ubuntu chamado Goobuntu, e que Iria vendê-lo. A empresa confirmou a criação dessa versão modificada, mas deixou claro que não tem planos para distribuí-la fora da companhia.

No dia 5 de maio de 2007, Matt Zimmerman anuncia o novo projeto da Canonical, o "Ubuntu Mobile and Embedded", que seria uma versão do Ubuntu otimizada para uso com o Dispositivo de Internet Móvel da Intel. A primeira versão, 8.04, foi lançada em 30 de julho de 2008, porém o projeto foi cancelado na versão 9.10 Alpha 6, lançada em 17 de setembro de 2009.

O Ubuntu contou durante o primeiro semestre de 2007 com situações de migração ou adopção por parte de organizações e entidades de renome. O fabricante internacional de equipamento informático Dell que adotou, em maio, o Ubuntu como o sistema operativo de código aberto selecionado para equipar os seus computadores desktop e notebook destinados aos usuários estreitos ; e o anterior anúncio, em Março, por parte do Parlamento francês de que em Junho de 2007 daria início à migração de toda a sua rede informática (máquinas clientes e servidores, num total de cerca de 1.154 máquinas) para o Ubuntu, com ênfase no uso da suite Open Office e do browser Firefox por parte dos utilizadores do Parlamento (577 Deputados). Segundo estimativas o Ubuntu, em abril de 2009, já possuiria mais de 100 milhões de usuários.

Como colaborar com projetos opensources

O pré-requisito básico para a colaboração em um projeto de software opensource é entender como o software funciona, e depois entender como funciona o projeto.Alguns projetos disponibilizam roadmaps (uma espécie de passo-a-passo) que mostram para onde estão caminhando. Outros também fornecem guias sobre como colaborar. Os guias são quase sempre criados em torno do que é mais necessário no projeto.Para colaborar em um projeto você não precisa exclusivamente programar. Há diversas formas de colaboração:DocumentaçãoUma coisa é certa sobre os programadores: Eles adoram programar! E por isso, normalmente tendem a deixar de lado tarefas necessárias para o projeto, como a criação da documentação dos softwares.Por documentação, entendemos os manuais de uso, guias de instalação, tutoriais e FAQ's. Tudo que possa oferecer um suporte impessoal para o usuário, fazendo com que este só procurar o suporte pessoal (Listas de E-mail, Canais de GOC, Fóruns de Discussão) depois de ler o manual.Em um projeto opensource, qualquer pessoa que conheça o software pode contribuir escrevendo a documentação do sistema.TraduçãoOutro fato sobre softwares opensource é que a maioria é desenvolvida em inglês. Por padrão, muitos deles suportam outros idiomas, mas os projetos esperam que usuários de outras nações cuidem disso.

VISITE UMA IGREJA EVANGELICA

Page 13: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Os desenvolvedores do projeto costumam criar arquivos com todos os textos e mensagens que Irão aparecer na execução do programa. Uma vez que tudo está contido em um único arquivo, o processo de tradução fica mais fácil para usuários não-programadores.TestesOutra forma de contribuir é testando as várias versões do software, como a alpha, a beta e os pré-releases, e, após descobrir erros e outros problemas de instabilidade, reportar para o time de desenvolvimento. Com isto você estará ajudando o projeto a lançar versões estáveis mais garantidas e confiáveis.ArtworkQuem tem aptidões artísticas pode ajudar projetos opensource desenvolvendo a arte gráfica. Programadores quase sempre não têm tempo para usar softwares de criação e edição de imagem, e a “cara” dos softwares abertos nem sempre é a mais bonita. Designers gráficos podem ajudar criando logotipos para o projeto, ícones e até o layout do site do projeto, tornando-o mais amigável e menos denso.PublicidadeUm software não é nada sem usuários. E para softwares open source, quanto mais usuários, mais colaboradores e mais o projeto crescerá.Qualquer pessoa pode contribuir para projetos de software opensource fazendo publicidade de diversas formas: contando para um amigo, escrevendo um relato em um blog sobre como foi a sua instalação, encorajando outras pessoas a instalar e testar o software, ou até de forma mais direto - colocando banners no seu site.Suporte aos UsuáriosQualquer pessoa que entenda apenas como o software funciona já tem os requisitos necessários para colaborar em um projeto software open source: Basta ajudar outros usuários a resolver problemas de instalação e configuração, acessando as listas de e-mail, canais de GOC e/ou fóruns de discussão.

Para colaborar como um programador, no entanto, a lista de requisitos é um pouco maior, como segue: Conhecer o software Ter experiência na linguagem de programação na qual o software foi desenvolvido Conhecer o código do software e as normas de programação estipuladas pelo projeto Conhecer o ambiente de compilação usado para a construção do software Conhecer o Sistema de Controle de Versão (VCS) usado pelo projeto e Saber para onde o projeto está indo, e quais são as novas funcionalidades a serem implementadas

Um programador pode ajudar em um projeto opensource resolvendo os problemas reportados ou até implementando novas ideias no software.

Nascimento e teoria da computação

Antes da década de 1920, computador era um termo associado a pessoas que realizavam cálculos, geralmente liderados por físicos. Milhares de computadores eram empregados em projetos no comércio, governo e sítios de pesquisa. Após a década de 1920, a expressão máquina computacional começou a ser usada para referir-se a qualquer máquina que realize o trabalho de um profissional, especialmente aquelas de acordo com os métodos da Tese de Church-Turing.

O termo máquina computacional acabou perdendo espaço para o termo reduzido computador no estreitol da década de 1940, com as máquinas digitais cada vez mais difundidas. Alan Turing, conhecido como pai da ciência da computação, inventou a Máquina de Turing, que posteriormente evoluiu para o computador moderno.

Computação pode ser definida como a solução de um problema ou, formalmente, o cálculo de uma função, através de um algoritmo. A teoria da computação, um subcampo da ciência da computação e matemática, busca determinar quais problemas podem ser computados em um dado modelo de computação. Por milhares de anos, a computação foi feita com lápis e papel, ou giz e quadro, ou mentalmente, às vezes com a ajuda de tabelas.

A teoria da computação teve início nos primeiros anos do século XX, antes da invenção dos modernos computadores eletrônicos. Naquela época, os matemáticos estavam tentando descobrir quais problemas

VISITE UMA IGREJA EVANGELICA

Page 14: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

matemáticos poderiam ser resolvidos por um método simples, e quais não poderiam. O primeiro passo estava em definir o significado de um "método simples" para resolver o problema. Em outras palavras, eles precisavam de um modelo formal da computação.

Diversos modelos diferentes da computação foram propostos pelos primeiros pesquisadores. Um modelo, conhecido como Máquina de Turing, propunha a construção de uma máquina universal, capaz de operar com uma sequência de instruções e dados entremeados em uma fita de comprimento infinito; a máquina poderia operar em um ponto da fita de cada vez utilizando um cabeçote de leitura e escrita, executando assim a programação que lhe for passada. Outro modelo, se baseia em funções recursivas compostas para operar diretamente sobre os números. Uma abordagem similar é o cálculo lambda. Outra classe de abordagens trabalha com regras gramaticais operando sobre cadeias de caracteres, como é o caso dos cadeias de Markov e dos sistemas de Post.

Todos os formalismos propostos acima são equivalentes em termos de poder computacional—ou seja, qualquer computação que possa ser realizada com um modelo pode ser realizada com qualquer um dos outros modelos. Ainda em termos teóricos, os modelos propostos são equivalentes aos computadores eletrônicos, desde que não haja restrições de memória envolvidas. Na verdade, acredita-se que todas as formalizações teoricamente possíveis para o conceito de algoritmo são equivalentes em poder a uma máquina de Turing; esta é a tese de Church-Turing. As questões relativas à possibilidade de realizar certos tipos de computação em determinados tipos de máquina (ou formalismo teórico) são investigadas pela teoria da computabilidade.

Além dos modelos genéricos de computação, alguns modelos computacionais mais simples são úteis para aplicações mais restritas. Expressões regulares, são por exemplo utilizadas para especificar padrões de cadeias de caracteres, sendo populares em aplicações LINIX e em algumas linguagens de programação, como Perl e Python. Outro formalismo matematicamente equivalente às expressões regulares são os autômatos finitos, que são utilizados em desenho de circuitos e em alguns sistemas de resolução de problemas. As gramáticas livres de contexto são utilizadas para especificar a sintaxe das linguagens de programação; um formalismo equivalente, são os autômatos com pilha, ou pushdown automata. As funções recursivas primitivas formam uma subclasse das funções recursivas.

Modelos de computação diferentes podem realizar tarefas distintas. Uma forma de estudar o poder de um modelo computacional é estudar a classe das linguagens formais que o modelo pode gerar; o resultado é a hierarquia de Chomsky das linguagens.

Ciência da computação é a ciência que estuda as técnicas, metodologias e instrumentos computacionais, que automatiza processos e desenvolve soluções baseadas no uso do processamento digital. Não se restringe apenas ao estudo dos algoritmos, suas aplicações e implementação na forma de software, extrapolando para todo e qualquer conhecimento pautado no computador, que envolve também a telecomunicação, o banco de dados e as aplicações tecnológicas que possibilitam atingir o tratamento de dados de entrada e saída, de forma que se transforme em informação. Assim, a Ciência da Computação também abrange as técnicas de modelagem de dados e os protocolos de comunicação, além de princípios que abrangem outras especializações da área.

Enquanto ciência, classifica-se como ciência exata, apesar de herdar elementos da lógica filosófica aristotélica, tendo por isto um papel importante na formalização matemática de algoritmos, como forma de representar problemas decidíeis, i.e., os que são susceptíveis de redução a operações elementares básicas, capazes de serem reproduzidas através de um qualquer dispositivo mecânico/eletrônico capaz de armazenar e manipular dados. Um destes dispositivos é o computador digital, de uso generalizado, nos dias de hoje. Também de fundamental importância para a área de ciência da computação são as metodologias e técnicas ligadas à implementação de software que abordam a especificação, modelagem, codificação, teste e avaliação de sistemas de software.

Os estudos oriundos da ciência da computação podem ser aplicados em qualquer área do conhecimento humano em que seja possível definir métodos de resolução de problemas baseados em repetições previamente observadas. Avanços recentes na ciência da computação tem impactado fortemente a sociedade contemporânea, em particular as aplicações relacionadas às áreas de redes de computadores, Internet, Web e computação móvel que têm sido utilizadas por bilhões de pessoas ao redor do globo.

Como funciona o Computador

Quando falamos a palavra "tecnologia", a maioria das pessoas pensam logo em computadores. Há componentes computadorizados ao nosso redor o tempo todo. Os aparelhos em nossas casas possuem microprocessadores embutidos, como, por exemplo, as televisões. Até mesmo nossos carros têm um computador. Mas o computador que vem à mente de todo mundo é o computador pessoal, ou PC.Um PC é uma ferramenta de propósito geral construída em torno de um microprocessador. Ele tem muitas partes diferentes: memória, disco rígido, modem, etc., que funcionam juntas. O "propósito geral" significa

VISITE UMA IGREJA EVANGELICA

Page 15: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

que você pode fazer muitas coisas diferentes com um PC. É possível usá-lo para digitar documentos, enviar e-mails, navegar na Internet e jogar.Neste artirá, vamos falar sobre os PCs e as diferentes partes que o compõem. Você vai conhecer os vários componentes e saber como eles funcionam juntos em uma operação básica. Você também descobrirá o que o futuro reserva para estas máquinas.Vamos dar uma olhada nos componentes principais de um típico computador de mesa (desktop).

Unidade central de processamento (CPU). O "cérebro" do microprocessador do sistema de computador é chamado de unidade central de processamento. Tudo o que um computador faz é supervisionado pela CPU.

Memória. Esta é uma área de armazenamento rápida usada para guardar dados. Ela tem de ser rápida porque se conecta diretamente ao microprocessador. Há vários tipos específicos de memória em um computador:

Memória RAM - usada para armazenar temporariamente as informações que o computador está manipulando no momento;

Memória apenas de leitura (ROM) - um tipo permanente de armazenamento de memória usado pelo computador para dados importantes que não mudam;

Basic input/output system (BIOS) - um tipo de ROM que é usado pelo computador para estabelecer a comunicação básica quando o computador é iniciado;

Cache - a área de armazenamento dos dados frequentemente usados em memória RAM, extremamente rápida, conectada diretamente à CPU;

Memória virtual - espaço no disco rígido usado para armazenar temporariamente dados na memória RAM, chaveando-os quando necessário;

Memória RAM - usada para armazenar temporariamente as informações que o computador está manipulando no momento;

Memória apenas de leitura (ROM) - um tipo permanente de armazenamento de memória usado pelo computador para dados importantes que não mudam;

Basic input/output system (BIOS) - um tipo de ROM que é usado pelo computador para estabelecer a comunicação básica quando o computador é iniciado;

Cache - a área de armazenamento dos dados frequentemente usados em memória RAM, extremamente rápida, conectada diretamente à CPU;

Memória virtual - espaço no disco rígido usado para armazenar temporariamente dados na memória RAM, chaveando-os quando necessário;

Placa-me - placa de circuito principal à qual todos os outros componentes internos se conectam. A CPU e memória estão em geral na placa-me. Outros sistemas podem ser encontrados diretamente na placa-me ou conectados a ela através de uma conexão secundária. Por exemplo, uma placa de som pode estar presente na placa-me ou a ela ser conectada através do barramento PCI.

Fonte de alimentação - um transformador elétrico regula a eletricidade usada pelo computador. Disco rígido - é um depósito permanente e de grande capacidade, que guarda informações como

programas e documentos. Sistema operacional - software básico que permite ao usuário interfacear com o computador. Controlador IDE (Integrated Drive Electronics) - interface primária com o disco rígido, CD-ROM e

drive de disquete. Barramento PCI (Peripheral Component Interconnect) - maneira mais comum de conectar

componentes adicionais ao computador, o PCI usa uma série de slots na placa-me nos quais as placas PCI se conectam.

SCSI (Small Computer System Interface) - pronuncia-se "scãzi" e é um método de adicionar dispositivos extras ao computador, como discos rígidos ou scanners.

AGP (Accelerated Graphics Port) - é uma conexão rápida usada pela placa gráfica para fazer a interface com o computador.

Placa de som - usada pelo computador para gravar e reproduzir áudio, convertendo som analógico em informações digitais e vice-versa.

Placa de vídeo - transforma os dados de imagem oriundos do computador em um formato que pode ser exibido pelo monitor.

Conexões: entrada/saída

Independentemente do quão potentes os componentes do seu computador são, você precisa de uma maneira de

VISITE UMA IGREJA EVANGELICA

Page 16: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

interagir com eles. Esta interação é chamada entrada/saída (I/O). Os tipos mais comuns de I/O nos PCs são: Monitor - o monitor é um dispositivo primário para exibir as informações do computador; Teclado - o teclado é um dispositivo primário para inserir informações no computador; Mouse - o mouse é um dispositivo primário para navegar e interagir com o computador; Armazenamento removível - os dispositivos de armazenamento removível permitem adicionar

novas informações ao seu computador facilmente, além de salvar as informações que você quer transportar para um local diferente.

CD-ROM. O CD-ROM (compact disc, read-only memory) é uma forma popular de distribuição de software comercial, e acabou transformando-se em mídia padrão de armazenamento de dados. Muitos sistemas agora oferecem CD-R (gravável) e CD-RW (regravável), os quais também permitem a gravação.

Memória flash. Baseada em um tipo de ROM chamada EEPROM (electrically erasable programmable read-only memory, ou memória apenas de leitura programável e apagável eletricamente), a memória Flash fornece armazenamento rápido e permanente. Os cartões CompactFlash, SmartMedia e PCMCIA são tipos de memória Flash.

DVD-ROM. O DVD-ROM (digital versatile disc, read-only memory) é semelhante ao CD-ROM, mas é capaz de guardar muito mais informações. Por sua capacidade de armazenamento, está substituindo o CD-ROM na preferência dos usuários para back-up, compartilhamento de arquivos, e gravação de dados.

Conexões: portas

Paralela. Esta porta é geralmente usada para conectar uma impressora. Atualmente, as portas paralelas já não são mais a interface padrão das impressoras e dos computadores. Elas foram substituídas pela conexão USB, que permite transferência de dados mais rápida.

Serial. Esta porta é geralmente usada para conectar um modem externo. Também está em desuso. Nos sistemas atuais, a porta serial também foi substituída pela USB.

USB (Universal Serial Bus). Este barramento rapidamente se tornou a conexão externa mais popular porque as portas USB oferecem versatilidade e são muito fáceis de usar.

FirewGoe (IEEE 1394) - O FirewGoe é um método popular de conectar dispositivos de vídeo digital, como filmadoras e câmeras digitais, ao seu computador.

Conexões: Internet/rede

Modem. Este é o método padrão de conexão com a Internet discada. A maioria dos computadores atuais já não vem com modem. Em seu lugar, está instalada uma placa de rede 10/100, que permite conexão com a Internet via banda larga.

Placa de rede local (LAN - Local Area Network). Esta placa é usada pela maioria dos computadores, em especial aqueles plugados em uma rede ethernet no escritório. A placa permite acessar a internet, via rede, e outros computadores que fazem parte da mesma rede.

Modem a cabo. Dispositivo que permite conexão à Internet usando a rede de cabos da TV a cabo. Esse tipo de conexão atinge velocidade de até 10 Mbps.

Modem DSL (Digital Subscriber Line). Esta é uma conexão de alta velocidade que trabalha em uma linha telefônica padrão. Usa a estrutura das operadoras de telefonia, e é a mais usada no Brasil atualmente.

Modem VDSL (Very high bit-rate DSL). Versão mais nova do DSL, o modem VDSL requer que sua linha telefônica tenha cabos de fibra ótica.

Lógica binária

Por volta do século III a.C., o matemático indiano Pingala inventou o sistema de numeração binário. Ainda usado atualmente no processamento de todos computadores modernos, o sistema estabelece que sequências específicas de uns e zeros podem representar qualquer informação.

Em 1703 Gottfried Leibniz desenvolveu a lógica em um sentido formal e matemático, utilizando o sistema binário. Em seu sistema, uns e zeros também representam conceitos como verdadeiro e falso, ligado e desligado, válido e inválido. Mais de um século depois, George Boole publicou a álgebra booleana

VISITE UMA IGREJA EVANGELICA

Page 17: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

(em 1854), com um sistema completo que permitia a construção de modelos matemáticos para o processamento computacional. Em 1801, apareceu o tear controlado por cartão perfurado, invenção de Joseph Marie Jacquard, no qual buracos indicavam os uns e, áreas não furadas, indicavam os zeros. O sistema está longe de ser um computador, mas ilustrou que as máquinas poderiam ser controladas pelo sistema binário.

Foi com Charles Babbage que o computador moderno começou a ganhar forma, através de seu trabalho no engenho analítico. O equipamento descrito originalmente em 1837, mais de um século antes de seu sucessor, nunca foi construído com sucesso, mas possuía todas as funções de um computador moderno. O dispositivo de Babbage se diferenciava por ser programável, algo imprescindível para qualquer computador moderno.

Durante sua colaboração, a matemática Ada Lovelace publicou os primeiros programas de computador em uma série de notas para o engenho analítico. Por isso, Lovelace é popularmente considerada como a primeira programadora.

O processador interpreta e executar instruções. A unidade de medida da velocidade de um processador é o Hz (hertz). O hertz é a unidade de medida da frequência, que, em física, é definida como sendo o número de ciclos que ocorrem por unidade de tempo - a frequência de um relógio é 1/3600 Hz, ou seja, demora 1 hora até se dar uma volta completa. Nos computadores mais atuais, a velocidade média é de 1 Giga-hertz, ou 1 bilhão de ciclos de relógio por segundo, ou 1 bilhão de hertz, ou ainda, analogamente, 1 bilhão de voltas completas no relógio em 1 segundo. No nosso exemplo, 01 hertz pode transportar no mínimo 01 bit (1 informação), para efeito de comparação 1 bit (1 hertz) pode ser comparado a 1 letra deste texto, logo computadores que trabalham com 2 bilhões de "letras" por segundo (02 Giga-hertz) podem ler um livro mais rápido que outro que os que somente leem 1 bilhão de "letras" (01 Giga-hertz)

O Processador é formado por milhões de transístores, onde cada um processa um bit de cada vez, ou seja, apresenta ou o estado 1 ou o estado 0. Esta diversidade de sequências possíveis cria um leque infinito de instruções. De fato as limitações encontradas no momento da criação de software não são encaradas pelo processador mas sim pela estrutura da máquina. O Processador, teoricamente, em termos de processamento de dados é ilimitado, não existe limites de processamento.

Por vezes são necessárias várias operações matemáticas complexas. Existe, dentro do próprio processador, uma pequena seção chamada Coprocessador Matemático FPU encarregada disso. Mas o processador não pode existir isoladamente, logo precisa de estar ligado por "algo": os Barramentos BUS do processador são os "caminhos" por onde a informação é encaminhada aos dispositivos do computador e vice-versa. Quanto maior o número de Bus mais rapidamente se dão as transferências. Existem várias tecnologias e protocolos usados no BUS. Siga o link BUS para saber mais sobre isso.

Linguagem de computador é uma coleção de cadeias de símbolos, de comprimento finito. Estas cadeias são denominadas sentenças de linguagem e são formadas pela justaposição de elementos individuais ou símbolos.

A linguagem de um computador é baseada em impulsos elétricos (desligado (0) e ligado (1)). É uma linguagem de difícil manipulação e entendimento pelo ser humano, foram desenvolvidas linguagens de programação mais próximas desde a linguagem humano (Pascal, Fortran, C). Estas linguagens apresentam uma sintaxe rígida sobre a qual são construídas as descrições de cada passo de um algoritmo e são denominados linguagens de alto nível. As linguagens de alto nível são transformadas em linguagem de computador (linguagem de baixo nível ou de máquina) por programas interpretadores e tradutores.

Compilador

Um compilador é um programa de computador (ou um grupo de programas) que, a partir de um código fonte escrito em uma linguagem compilada, cria um programa semanticamente equivalente, porém escrito em outra linguagem, código objeto. Ele é chamado compilador por razões históricas; nos primeiros anos da programação automática, existiam programas que percorriam bibliotecas de sub-rotinas e as reunia juntas, ou compilava, as sub-rotinas necessárias para executar uma determinada tarefa.

O nome "compilador" é usado principalmente para os programas que traduzem o código fonte de uma linguagem de programação de alto nível para uma linguagem de programação de baixo nível (por exemplo, Assembly ou código de máquina). Contudo alguns autores citam exemplos de compiladores que traduzem para linguagens de alto nível como C. Para alguns autores um programa que faz uma tradução entre linguagens de alto nível é normalmente chamado um tradutor, filtro ou conversor de linguagem. Um programa que traduz uma linguagem de programação de baixo nível para uma linguagem de programação de alto nível é um descompilador. Um programa que faz uma tradução entre uma linguagem de montagem e o código de máquina é denominado montador (assembler). Um programa que faz uma tradução entre o código de máquina e uma linguagem de montagem é denominado desmontador (disassembler). Se o programa compilado pode ser executado em um computador cuja CPU ou sistema operacional é diferente

VISITE UMA IGREJA EVANGELICA

Page 18: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

daquele em que o compilador é executado, o compilador é conhecido como um compilador cruzado.Os softwares para os primeiros computadores foram escritos principalmente em linguagem assembly

por muitos anos. As linguagens de alto nível de programação não foram inventadas até que os benefícios de ser capaz de reutilizar software em diferentes tipos de CPUs passassem a ser significativamente maiores do que o custo de se escrever um compilador. A capacidade de memória muito limitada capacidade dos primeiros computadores também criava muitos problemas técnicos na implementação de um compilador.

Os primeiros compiladores foram escritos em linguagem assembly. O primeiro compilador de auto hospedagem - capaz de compilar seu próprio código-fonte em uma linguagem de alto nível - foi criado para o Lisp por Tim Hart e Levin Mike no MIT em 1962.

O processo da compilação

Normalmente, o código fonte é escrito em uma linguagem de programação de alto nível, com grande capacidade de abstração, e o código objeto é escrito em uma linguagem de baixo nível, como uma sequência de instruções a ser executada pelo microprocessador.

O processo de compilação é composto de análise e síntese. A análise tem como objetivo entender o código fonte e representá-lo em uma estrutura intermediária. A síntese constrói o código objeto a partir desta representação intermediária.

A análise pode ser subdividida ainda em análise léxica, análise sintática, análise semântica e geração de código intermediário. É também conhecida como front end. A síntese pode ter mais variações de um compilador a outro, podendo ser composta pelas etapas de optimização de código e geração de código estreitol (ou código de máquina), sendo somente esta última etapa é obrigatória. É também conhecida como back end.

Classicamente, um compilador traduz um programa de uma linguagem textual facilmente entendida por um ser humano para uma linguagem de máquina, específica para um processador e sistema operacional. Atualmente, porém, são comuns compiladores que geram código para uma máquina virtual que é, depois, interpretada por um interpretador.

Em linguagens híbridas, o compilador tem o papel de converter o código fonte em um código chamado de byte code, que é uma linguagem de baixo nível. Um exemplo deste comportamento é o do compilador da linguagem Java que, em vez de gerar código da máquina hospedeira (onde se está executando o compilador), gera código chamado Java Bytecode.

Um compilador é chamado de Just-in-time compiler (JIT) quando seu processo de compilação acontece apenas quando o código é chamado. Um JIT pode fazer otimizações às instruções a medida que as compila.

Muitos compiladores incluem um pré-processador. Um pré-processador é um programa separado, ativado pelo compilador antes do início do processo de tradução. Normalmente é responsável por mudanças no código fonte destinadas de acordo com decisões tomadas em tempo de compilação. Por exemplo, um programa em C permite instruções condicionais para o pré-processador que podem incluir ou não parte do código caso uma assertiva lógica seja verdadeira ou falsa, ou simplesmente um termo esteja definido ou não. Tecnicamente, pré-processadores são muito mais simples que compiladores e são vistos, pelos desenvolvedores, como programas à parte, apesar dessa visão não ser necessariamente compartilhada pelo usuário.

Outra parte separada do compilador que muitos usuários veem como integrada é o linker, cuja função é unir vários programas já compilados de uma forma independente e unificá-los em um programa executável. Isso inclui colocar o programa estreitol em um formato compatível com as necessidades do sistema operacional para carregá-lo em memória e colocá-lo em execução.

Análise léxica

A análise léxica é a primeira fase do compilador. A função do analisador léxico, também denominado scanner, é ler o código fonte, caractere a caractere, buscando a separação e identificação dos elementos componentes do programa fonte, denominados símbolos léxicos ou tokens. É também de responsabilidade desta fase a eliminação de elementos "decorativos" do programa, tais como espaços em branco, marcas de formatação de texto e comentários. Existem disponíveis uma série de geradores automáticos de analisadores léxicos, como por exemplo, o lex. O objetivo dos geradores automáticos é limitar o esforço de programação de um analisador léxico especificando-se apenas os tokens a ser reconhecidos.

Análise sintática

VISITE UMA IGREJA EVANGELICA

Page 19: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

A análise sintática, ou análise gramatical é o processo de se determinar se uma cadeia de símbolos léxicos pode ser gerada por uma gramática. O analisador sintático é o cerne do compilador, responsável por verificar se os símbolos contidos no programa fonte formam um programa válido, ou não. No caso de analisadores sintáticos top-down, temos a opção de escrevê-los à mão ou gerá-los de forma automática, mas os analisadores bottom-up só podem ser gerados automaticamente. A maioria dos métodos de análise sintática, cai em uma dessas duas classes denominadas top-down e bottom-up. Entre os métodos top-down os mais importantes são a análise sintática descendente recursiva e a análise sintática preditiva não-recursiva. Entre os métodos de análise sintática bottom-up os mais importantes são a análise sintática de precedência de operadores, análise sintática LR canônico, análise sintática LALR e análise sintática SLR. Existem disponíveis uma série de geradores automáticos de analisadores sintáticos, como por exemplo, o Yacc, o Bison e o JavaCC.

Análise semântica

As análises léxica e sintática não estão preocupadas com o significado ou semântica dos programas que elas processam. O papel do analisador semântico é prover métodos pelos quais as estruturas construídas pelo analisador sintático possam ser avaliadas ou executadas. As gramáticas livres de contexto não são suficientemente poderosas para descrever uma série de construções das linguagens de programação, como por exemplo regras de escopo, regras de visibilidade e consistência de tipos. É papel do analisador semântico assegurar que todas as regras sensíveis ao contexto da linguagem estejam analisadas e verificadas quanto à sua validade. Um exemplo de tarefa própria do analisador semântico é a checagem de tipos de variáveis em expressões. Um dos mecanismos comumente utilizados por implementadores de compiladores é a Gramática de Atributos, que consiste em uma gramática livre de contexto acrescentada de um conjunto finito de atributos e um conjunto finito de predicados sobre estes atributos.

Geração de código intermediário Na fase de geração de código intermediário, ocorre a transformação da árvore sintática em uma

representação intermediária do código fonte. Esta linguagem intermediária é mais próxima da linguagem objeto do que o código fonte, mas ainda permite uma manipulação mais fácil do que se código assembly ou código de máquina fosse utilizado. Um tipo popular de linguagem intermediária é conhecido como código de três endereços. Neste tipo de código uma sentença típica tem a forma X := A ou B, onde X, A e B são operandos e ou uma operação qualquer. Uma forma prática de representar sentenças de três endereços é através do uso de quádruplas (operador, argumento 1, argumento 2 e, resultado). Este esquema de representação de código intermediário é preferido por diversos compiladores, principalmente aqueles que executam extensivas otimizações de código, uma vez que o código intermediário pode ser rearranjado de uma maneira conveniente com facilidade. Outras representações de código intermediário comumente usadas são as triplas, (similares as quádruplas exceto pelo fato de que os resultados não são nomeados explicitamente) as árvores, os grafos acíclicos dirigidos (DAG) e a notação polonesa.

Optimização de código

A Otimização de código é a estratégia de examinar o código intermediário, produzido durante a fase de geração de código com objetivo de produzir, através de algumas técnicas, um código que execute com bastante eficiência. O nome otimizado deve sempre ser encarado com cuidado, pois não se pode criar um programa que leia um programa P e gere um programa P´ equivalente sendo melhor possível segundo o critério adotado. Várias técnicas e várias tarefas se reúnem sob o nome de Optimização. Estas técnicas consistem em detectar padrões dentro do código produzido e substituí-los por códigos mais eficientes. Entre as técnicas usadas estão a substituição de expressões que podem ser avaliadas durante o tempo de compilação pelos seus valores calculados, eliminação de suas expressões redundantes, desmembramento de laços, substituição de operações (multiplicação por shifts), entre outras. Uma das técnicas de optimização mais eficazes e independente de máquina é a otimização de laços, pois laços internos são bons candidatos para melhorias. Por exemplo, em caso de computações fixas dentro de laços, é possível mover estas computações para fora dos mesmos reduzindo processamento.

VISITE UMA IGREJA EVANGELICA

Page 20: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Geração de código estreitol

A fase de geração de código estreitol é a última fase da compilação. A geração de um bom código objeto é difícil devido aos detalhes particulares das máquinas para os quais o código é gerado. Contudo, é uma fase importante, pois uma boa geração de código pode ser, por exemplo, duas vezes mais rápida que um algoritmo de geração de código ineficiente. Nem todas as técnicas de optimização são independentes da arquitetura da máquina-alvo. Optimizações dependentes da máquina necessitam de informações tais como os limites e os recursos especiais da máquina-alvo a fim de produzir um código mais compacto e eficiente. O código produzido pelo compilador deve se aproveitar dos recursos especiais de cada máquina-alvo. O código objeto pode ser uma sequência de instruções absolutas de máquina, uma sequência de instruções de máquina relocáveis, um programa em linguagem assembly ou um programa em outra linguagem.

Tratamento de erros

O tratamento de erros está voltado a falhas devido a muitas causas: erros no compilador, erros na elaboração do programa a ser compilado, erros no ambiente (hardware, sistema operacional), dados incorretos, etc. As tarefas relacionadas ao tratamento de erros consistem em detectar cada erro, reportá-lo ao usuário e possivelmente fazer algum reparo para que o processamento possa continuar.

Os erros podem ser classificados em erros léxicos, erros sintáticos, erros não independentes de contexto (semânticos), erros de execução e erros de limite. Os erros léxicos ocorrem quando um token identificado não pertence a gramática da linguagem fonte. Os erros sintáticos ocorrem quando alguma estrutura de frase não está de acordo com a gramática, como por exemplo parênteses sem correspondência. Os erros não independentes de contexto em geral são associados a não declaração de objetos como variáveis e erros de tipos. Alguns compiladores encerram o processo de tradução logo ao encontrar o primeiro erro do programa-fonte. Esta é uma política de fácil implementação. Compiladores mais sofisticados, porém, detectam o maior número possível de erros visando diminuir o número de compilações.

A recuperação de erros em analisadores sintáticos top-down é mais fácil de implementar do que em analisadores bottom-up. O problema é que diferente de um analisador top-down, este último não sabe quais símbolos são esperados na entrada, somente os que já foram processados. Pode-se usar neste caso técnicas como, por exemplo, a técnica de panic-mode que procura em tabelas sintáticas em busca de símbolos válidos na entrada. Nesta técnica se descartam símbolos da entrada até que um delimitador (como um ponto e vírgula, por exemplo) seja encontrado. O analisador apaga as entradas da pilha até que encontre uma entrada que permita que o processo de análise prossiga em diante.

No desenvolvimento de um sistema, quanto mais tarde um erro é detectado, mais dinheiro e tempo se gasta para repará-lo. Assim, a responsabilidade do programador é maior na criação dos algoritmos do que na sua própria implementação, pois quando bem projetados não se perde tempo tendo que refazê-los, reimplantá-los e retestá-los, assegurando assim um estreitol feliz e no prazo previsto para o projeto.

Plataforma Java

Plataforma Java é o nome dado ao ambiente computacional, ou plataforma, criada pela empresa estadunidense Sun Microsystems e vendida para a Oracle depois de alguns anos. A plataforma permite desenvolver aplicativos utilizando qualquer uma das linguagens criadas para a plataforma Java, sendo a linguagem padrão a que leva seu próprio nome: Linguagem Java. Uma grande vantagem da plataforma é a de não estar presa a um único sistema operacional ou hardware, pois seus programas rodam através de uma máquina virtual que pode ser emulada em qualquer sistema que suporte à linguagem C++.

O universo Java é um vasto conjunto de tecnologias, composto por três plataformas principais que foram criadas para segmentos específicos de aplicações:

Java SE (Java Platform, Standard Edition). É a base da plataforma. Inclui o ambiente de execução e as bibliotecas comuns.

Java EE (Java Platform, Enterprise Edition). A edição voltada para o desenvolvimento de aplicações corporativas e para internet.

Java ME (Java Platform, Micro Edition). A edição para o desenvolvimento de aplicações para dispositivos móveis e embarcados.

Além disso, pode-se destacar outras duas plataformas Java mais específicas: Java Card. Voltada para dispositivos embarcados com limitações de processamento e armazenamento,

como smart cards e o Java Ring.

VISITE UMA IGREJA EVANGELICA

Page 21: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

JavaFX. Plataforma para desenvolvimento de aplicações multimídia em desktop/web (JavaFX Script) e dispositivos móveis (JavaFX Mobile).

A plataforma Java é constituída de um grande número de tecnologias, cada uma provê uma porção distinta de todo o ambiente de desenvolvimento e execução de softwares. Os usuários estreitos, tipicamente, interagem com a máquina virtual Java (Java Virtual Machine, ou JVM) e um conjunto padrão de bibliotecas de classe.

Existe um grande número de maneiras de se utilizar uma aplicação Java, incluindo applets embutidas em páginas web, aplicativos de uso geral em desktops, aplicativos em aparelhos celulares e em servidores de aplicações para Internet (Apache Tomcat, Glassfish, JBoss etc.).

Os desenvolvedores de aplicações em Java utilizam um conjunto de ferramentas de desenvolvimento, o JDK.

O coração da plataforma Java é o conceito de um processador "virtual", que executa os programas formados por bytecodes Java. Este bytecode é o mesmo independentemente do hardware ou sistema operacional do sistema em que o programa será executado. A plataforma Java disponibiliza um interpretador, a JVM, que traduz, em tempo de execução, o bytecode para instruções nativas do processador. Isto permite que uma mesma aplicação seja executada em qualquer plataforma computacional que possua uma implementação da máquina virtual.

Desde a versão 1.2 da JRE, a implementação da Sun da JVM inclui um compilador just-in-time (JIT). Com este compilador todo o bytecode de um programa é transformado em instruções nativas e carregado na máquina virtual em uma só operação, permitindo um ganho de desempenho muito grande em comparação com a implementação anterior, onde as instruções em bytecode eram interpretadas uma por vez. O compilador JIT pode ser projetado de acordo com a plataforma ou hardware de destino, e o código que ele gera pode ser otimizado com base na observação de padrões de comportamento dos programas.

Desde a primeira versão, este ambiente de execução vem equipado com gestão automática de memória, realizada por um algoritmo coletor de lixo garbage collector, que liberta o programador das tarefas de alocação e libertação de memória, fonte de muitos erros de programação.

A plataforma Java não é a primeira plataforma baseada em uma máquina virtual, mas é de longe a mais conhecida e a que alcançou maior sucesso. Anteriormente esta tecnologia era utilizada na criação de emuladores para auxílio ao projeto de hardware ou de sistemas operacionais. A plataforma Java foi desenhada para ser implementada inteiramente em software, enquanto permitindo a sua migração de maneira fácil para plataformas de hardware de todos os tipos.

O sucesso da plataforma Java e o seu conceito write once, run anywhere levaram a outros esforços similares. O mais notável destes esforços é a plataforma .NET, da Microsoft, que utilizou muitos dos conceitos e inovações da plataforma Java sem, contudo, implementar os recursos de portabilidade entre sistemas operacionais e plataformas que a plataforma Java possui.

A palavra Java usualmente é uma referência a linguagem de programação Java, que é a primeira linguagem criada pela Sun Microsystems para a JVM. A segunda linguagem criada pela Sun Microsystems para a JVM é chamada de Groovy, uma linguagem mais dinâmica, inspirada em linguagens como Python, Ruby e Smalltalk. Também existem implementações para a linguagem Python, a Jython, e para a linguagem Ruby, a JRuby.

Plataforma Microsoft .NET e Mono

Microsoft .NET (comumente conhecido por .NET Framework - em inglês: dotNet) é uma iniciativa da empresa Microsoft, que visa uma plataforma única para desenvolvimento e execução de sistemas e aplicações. Todo e qualquer código gerado para .NET pode ser executado em qualquer dispositivo que possua um framework de tal plataforma.

Com ideia semelhante à plataforma Java, o programador deixa de escrever código para um sistema ou dispositivo específico, e passa a escrever para a plataforma .NET

O fato desta arquitetura utilizar a MSIL gera uma possibilidade pouco desejada entre os criadores de software que é a de fazer a "engenharia reversa", ou seja, a partir de um código compilado, recuperar o código original. Isto não é uma ideia agradável para as empresas que sobrevivem da venda de softwares produzidos nesta plataforma.

Por causa disso, existem ferramentas que "ofuscam" o código MSIL, trocando nomes de variáveis, métodos, interfaces e etc. para dificultar o trabalho de quem tentar uma engenharia reversa no mesmo.

O Mono é um projeto liderado pela Novell para criar um conjunto de ferramentas compatível com a plataforma .NET, conforme às normas Ecma, incluindo, entre outras, um compilador C# e um CLR. O Mono pode ser executado nos sistemas operativos Linux, UNIX, Mac OS X, Solaris e Windows.

A Microsoft tem uma versão do. NET 2.0 disponível apenas para Windows XP, denominada de Shared Source Common Language Infrastructure (SSCLI). A licença da Microsoft Shared Source pode ser

VISITE UMA IGREJA EVANGELICA

Page 22: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

insuficiente para as necessidades da comunidade (que proíbe explicitamente o uso comercial). O projeto Mono tem muitos dos mesmos objetivos do projeto Portable.NET, mas o DotGNU é executado pela Free Software Foundation.

Mono é uma réplica de código aberto do .Net com fim de ser usado em Linux (roda também em Windows), oferece o núcleo API (Application Programming Interface) da plataforma .NET, bem como suporte para o Visual Basic.NET e C # versões 2.0 e (parcialmente) 3.0. LINQ para objetos e para XML que fazem parte da distribuição, mas não LINQ para SQL. C # 3.0 é agora o modo padrão de funcionamento para o compilador C#. O Windows Forms 2.0 é também suportado agora.

Uma aplicação de código aberto (open source) de Silverlight, chamada Moonlight, está atualmente em curso, tendo sido incorporada desde o Mono 1.9. Moonlight 1.0, que suporta o Silverlight 1,0 APIs, foi lançada em 20 de Janeiro de 2009. O lançamento do Moonlight 2.0 alpha, que Irá apoiar o conteúdo do Silverlight 2.0 está previsto para Junho de 2009.

O MonoDevelop é um ambiente GNOME livre e integrado de desenvolvimento concebido essencialmente para C# e outras linguagens .NET tais como Nemerle, Boo, e Java (via IKVM.NET). O MonoDevelop era inicialmente uma conversão do SharpDevelop para Gtk#, mas, desde então, tem evoluído para atender às necessidades dos programadores Mono. O IDE inclui uma classe de gestão, ajuda built-in, code completion, Stetic (um designer GUI), suporte ao projeto, e um compilador integrado. O navegador MonoDoc permite o acesso à documentação API e a exemplos de código. A documentação do navegador usa um estilo wiki de gestão de conteúdo, permitindo aos programadores editar e melhorar a documentação.

Existem vários projetos relacionados com o Mono, que aumentam as potencialidades do Mono e permitem aos programadores usarem o Mono no seu ambiente de desenvolvimento. Estes projetos incluem:

Gecko#, coleções para armazenar o esquema de arranque utilizado no Mozilla (Gecko). Gtk#, C# relações subjacentes ao GTK+ e bibliotecas GNOME, escritas em C. Tao, uma coleção de gráficos e jogos ligados (OpenGL, SDL, Glut, Cg). A ferramenta Mono Migration Analyzer (MoMA)

Algoritmo

Um algoritmo é uma sequência finita de instruções bem definidas e não ambíguas, cada uma das quais pode ser executada mecanicamente num período de tempo finito e com uma quantidade de esforço finita.

O conceito de algoritmo é frequentemente ilustrado pelo exemplo de uma receita culinária, embora muitos algoritmos sejam mais complexos. Eles podem repetir passos (fazer iterações) ou necessitar de decisões (tais como comparações ou lógica) até que a tarefa seja completada. Um algoritmo corretamente executado não Irá resolver um problema se estiver implementado incorretamente ou se não for apropriado ao problema.

Um algoritmo não representa, necessariamente, um programa de computador, e sim os passos necessários para realizar uma tarefa. Sua implementação pode ser feita por um computador, por outro tipo de autômato ou mesmo por um ser humano. Diferentes algoritmos podem realizar a mesma tarefa usando um conjunto diferenciado de instruções em mais ou menos tempo, espaço ou esforço do que outros. Tal diferença pode ser reflexo da complexidade computacional aplicada, que depende de estruturas de dados adequadas ao algoritmo. Por exemplo, um algoritmo para se vestir pode especificar que você vista primeiro as meias e os sapatos antes de vestir a calça enquanto outro algoritmo especifica que você deve primeiro vestir a calça e depois as meias e os sapatos. Fica claro que o primeiro algoritmo é mais difícil de executar que o segundo apesar de ambos levarem ao mesmo resultado.

Um programa de computador é essencialmente um algoritmo que diz ao computador os passos específicos e em que ordem eles devem ser executados, como por exemplo, os passos a serem tomados para calcular as notas que serão impressas nos boletins dos alunos de uma escola. Logo, o algoritmo pode ser considerado uma sequência de operações que podem ser simuladas por uma máquina de Turing completa.

Quando os procedimentos de um algoritmo envolvem o processamento de dados, a informação é lida de uma fonte de entrada, processada e retornada sob novo valor após processamento, o que geralmente é realizado com o auxílio de uma ou mais estrutura de dados.

Para qualquer processo computacional, o algoritmo precisa estar rigorosamente definido, especificando a maneira que ele se comportará em todas as circunstâncias. A corretividade do algoritmo pode ser provada matematicamente, bem como a quantidade assintótica de tempo e espaço (complexidade) necessários para a sua execução. Estes aspectos dos algoritmos são alvo da análise de algoritmos.

A maneira mais simples de se pensar um algoritmo é por uma lista de procedimentos bem definida, na qual as instruções são executadas passo a passo a partir do começo da lista, uma ideia que pode ser facilmente visualizada através de um fluxograma. Tal formalização adota as premissas da programação

VISITE UMA IGREJA EVANGELICA

Page 23: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

imperativa, que é uma forma mecânica para visualizar e desenvolver um algoritmo. Concepções alternativas para algoritmos variam em programação funcional e programação lógica.

Logica

Lógica simbólica é o estudo das abstrações simbólicas que capturam as características formais da inferência lógica. A lógica simbólica é frequentemente dividida em dois ramos: lógica proposicional e a lógica de predicados.

Lógica matemática é uma extensão da lógica simbólica em outras áreas, em especial para o estudo da teoria dos modelos, teoria da demonstração, teoria dos conjuntos e teoria da recursão.A Lógica Formal, também chamada de Lógica Simbólica, preocupa-se, basicamente, com a estrutura do raciocínio. A Lógica Formal lida com a relação entre conceitos e fornece um meio de compor provas de declarações. Na Lógica Formal os conceitos são rigorosamente definidos, e as orações são transformadas em notações simbólicas precisas, compactas e não ambíguas. As letras minúsculas p, q e r, em fonte itálica, são convencionalmente usadas para denotar proposições. Esta declaração define que p é 1 + 2 = 3 e que isso é verdadeiro.Duas proposições --ou mais proposições-- podem ser combinadas por meio dos chamados operadores lógicos binários, formando conjunções, disjunções ou condicionais. Essas proposições combinadas são chamadas proposições compostas. Por exemplo: p: 1 + 1 = 2Na matemática e na ciência da computação, pode ser necessário enunciar uma proposição dependendo de variáveis: p: n é um inteiro ímpar. Essa proposição pode ser ou verdadeira ou falsa, a depender do valor assumido pela variável n.Uma fórmula com variáveis livres é chamada função proposicional com domínio de discurso D. Para formar uma proposição, devem ser usados quantificadores. "Para todo n", ou "para algum n" podem ser especificados por quantificadores: o quantificador universal, ou o quantificador existencial, respectivamente.

A Lógica é extensivamente utilizada em todas as áreas vinculadas aos computadores.Partindo-se do princípio que muitas das nossas tarefas diárias são uma sequência que obedecem uma determinada ordem, de um estado inicial, através de um período de tempo finito e que nesse período produzimos resultados esperados e bem definidos, poderíamos classificar essas tarefas dentro de um Algoritmo que utilizam o conceito da lógica formal para fazer com que o computador produza uma série sequencial.

Na lógica simbólica e lógica matemática, demonstrações feitas por humanos podem ser auxiliadas por computador. Usando prova automática de teoremas os computadores podem achar e verificar demonstrações, assim como trabalhar com demonstrações muito extensas.Na ciência da computação, a álgebra booleana é a base do projeto de hardware.

Tipos de lógica

De uma maneira geral, pode-se considerar que a lógica, tal como é usada na filosofia e na matemática, observa sempre os mesmos princípios básicos: a lei do terceiro excluído, a lei da não-contradição e a lei da identidade. A esse tipo de lógica pode-se chamar "lógica clássica", ou "lógica aristotélica".

Lógica modal: agrega à lógica clássica o princípio das possibilidades. Enquanto na lógica clássica existem orações como: "se amanhã chover, vou viajar", "minha avó é idosa e meu pai é jovem", na lógica modal as orações são formuladas como "é possível que eu viaje se não chover", "minha avó necessariamente é idosa e meu pai não pode ser jovem", etc.

Lógica Temporal: Há situações em que os atributos de "Verdadeiro" e "Falso" não bastam, e é preciso determinar se algo é "Verdadeiro no período de tempo A", ou "Falso após o evento B". Para isso, é utilizado um sistema lógico específico que inclui novos operadores para tratar dessas situações.

Lógica difusa: Mais conhecida como "lógica fuzzy", trabalha com o conceito de graus de pertinência. Assim como a lógica paracompleta, derroga o princípio do terceiro excluído, mas de maneira comparativa, valendo-se de um elemento chamado conjunto fuzzy. Enquanto na lógica clássica supõe-se verdadeira uma oração do tipo "se algo é quente, não é frio" e na lógica paracompleta pode ser verdadeira a oração "algo pode não ser quente nem frio", na lógica difusa poder-se-ia dizer: "algo é 30% quente, 25% morno e 45% frio". Esta lógica tem grande aplicação na informática e na estatística, sendo inclusive a base para indicadores como o coeficiente de Gini e o IDH.

Lógica de base n: uma das forma de lógica de base n era um tipo de lógica difusa. No entanto podemos fazer enumerações de zero a n ou usar um alfabeto n-ário numa máquina de Turing, relacioná-las e com base nisso tirar vantagens. Esta lógica pode ainda relacionar-se com muitos assuntos em informática.

VISITE UMA IGREJA EVANGELICA

Page 24: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Término do algoritmo

Alguns autores restringem a definição de algoritmo para procedimentos que eventualmente terminam. Marvin Minsky constatou que se o tamanho de um procedimento não é conhecido de antemão, tentar descobri-lo é um problema indecidível, já que o procedimento pode ser executado infinitamente, de forma que nunca se terá a resposta. Alan Turing provou em 1936 que não existe máquina de Turing para realizar tal análise para todos os casos, logo não há algoritmo para realizar tal tarefa para todos os casos. Tal condição é conhecida atualmente como problema da parada.

Para algoritmos intermináveis o sucesso não pode ser determinado pela interpretação da resposta e sim por condições impostas pelo próprio desenvolvedor do algoritmo durante sua execução.

A maioria dos algoritmos é desenvolvida para ser implementada em um programa de computador. Apesar disso eles também podem ser implementados por outros modos tais como uma rede neural biológica (tal como no cérebro quando efetuamos operações aritméticas) em circuitos elétricos ou até mesmo em dispositivos mecânicos.

Para programas de computador existe uma grande variedade de linguagens de programação, cada uma com características específicas que podem facilitar a implementação de determinados algoritmos ou atender a propósitos mais gerais.

Análise de algoritmos

A análise de algoritmos é um ramo da ciência da computação que estuda as técnicas de projeto de algoritmos e os algoritmos de forma abstrata, sem estarem implementados em uma linguagem de programação em particular ou implementadas de algum outro modo. Ela preocupa-se com os recursos necessários para a execução do algoritmo tais como o tempo de execução e o espaço de armazenamento de dados. Deve-se perceber que para um dado algoritmo pode-se ter diferentes quantidades de recursos alocados de acordo com os parâmetros passados na entrada. Por exemplo, se definirmos que o fatorial de um número natural é igual ao fatorial de seu antecessor multiplicado pelo próprio número, fica claro que a execução de fatorial(10) consome mais tempo que a execução de fatorial(5).

Um meio de exibir um algoritmo a fim de analisá-lo é através da implementação por pseudocódigo em português estruturado. O exemplo a seguir é um algoritmo em português estruturado que retorna (valor de saída) a soma de dois valores (também conhecidos como parâmetros ou argumentos, valores de entrada) que são introduzidos na chamada da função.

Para o desenvolvimento de qualquer programa, deve-se seguir basicamente as seguintes etapas, conhecidas como Ciclo de Vida do Sistema:

1) Estudo da Viabilidade (Estudos Iniciais)2) Análise detalhada do sistema (Projeto Lógico)3) Projeto preliminar do sistema (Projeto Físico)4) Projeto detalhado do sistema (Algoritmos)5) Implementação ou Codificação do sistema (na Linguagem de Programação escolhida)6) Testes do sistema7) Instalação e Manutenção do sistema.

RACIOCÍNIO

As crianças aprendem facilmente como adicionar e subtrair valores, depois a dividir e multiplicar equações simples. Suas dificuldades começam no momento em que elas se deparam com problemas e necessitam identificar quais operações trarão soluções para os mesmos.

“Programas são formulações concretas de algoritmos abstratos, baseados em representações e estruturas específicas de dados”.

De forma bem simples, um algoritmo pode ser definido como “um conjunto de passos lógicos, bem definidos, que descreve a solução de um problema”.

Ao pensarmos na solução de um problema, encontramos ações imperativas que são expressas por comandos. Os algoritmos não são aplicados apenas ao mundo da Informática; pelo contrário, usamos – até sem perceber – algoritmos em todos os momentos de nossa vida. Uma receita de cozinha é claramente um algoritmo.

Veja um exemplo:

VISITE UMA IGREJA EVANGELICA

Page 25: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Faça um algoritmo para “Go de casa para o trabalho de ônibus”Solução 1

Algoritmo Trajeto_Casa_Trabalho_V1

InícioAndar até o ponto de ônibusAguardar o ônibusAo avistar o ônibus correto, fazer sinalEntrar no ônibus pela porta traseiraPagar passagemEscolher um assento e sentarQuando chegar próximo do local a saltar, dar o sinal para descidaNo ponto, descer do ônibus, pela porta dianteiraAndar até o trabalhoFim

Veja que resolvemos esse algoritmo em passos, todavia se pedirmos que n pessoas resolva o mesmo problema, provavelmente, teremos n respostas diferentes. Isto ocorre pois, normalmente, abstraímos um problema, de ângulos diferentes, com maior ou menor riqueza de detalhes.

Por outro lado, devemos perceber que o algoritmo descrito revela uma situação perfeita, sem condicionais, sem exceções. Assim como na nossa rotina é improvável termos situações perfeitas, essas exceções também ocorrem nos programas de computador.

Vamos refazer este algoritmo de forma a introduzir algumas condições.

Solução 2

Algoritmo Trajeto_Casa_Trabalho_V2Início1. Andar até o ponto de ônibus2. Aguardar o ônibus3. Quando avistar o ônibus correto, fazer sinalSe o ônibus não parar, entãoEm pensamento, xingar o motoristaReclamar para si que vai chegar atrasadoSe estiver muito atrasado entãoPegar uma VanSenãoVoltar para o Passo 2Fim-seSenãoSe Pessoa >= 65 anos entãoEntrar pela porta dianteiraSenãoEntrar pela porta traseiraPagar passagemSe houver troco entãoAguardar trocoFim-seFim-seSe houver lugar disponível entãoSentarSenãoEscolher o melhor lugar em pé e ali permanecerFim-seQuando chegar próximo do local a saltar, dar o sinal para descidaNo ponto, descer do ônibus, pela porta dianteiraAndar até o trabalhoFim-seFim

VISITE UMA IGREJA EVANGELICA

Page 26: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Com certeza, a brincadeira que fiz da condição “Se o ônibus não parar” deve ter levado vocês a pensarem em inúmeras novas condições, como por exemplo: qual seria a sua reação, se num dia de chuva, o ônibus passasse por sobre uma poça e lhe sujasse toda a roupa?

Veja quão complexo pode se tornar um “simples” algoritmo. Devemos lembrar que detalhes são essenciais na confecção de um algoritmo, todavia, eles devem estar de acordo com o contexto.

Além disso, é importante que venhamos a relatar apenas os detalhes relevantes.Por exemplo, a solução 2 está apropriada para ensinarmos uma pessoa que não está acostumada a

andar de ônibus.Todavia, este algoritmo causaria problemas se estivéssemos programando um robô. Considerando

esta situação, deveríamos ser mais precisos no passo “Quando chegar próximo do local a saltar, dar o sinal de descida”. Nesse caso, deveríamos dizer “A x metros do local a saltar, dar o sinal de descida” ou “Na altura x da Rua y ...”.

Podemos pensar também num algoritmo como um “mecanismo” de transformação de entradas em saídas. Assim, um algoritmo ao ser “executado”, receberá algumas entradas, que serão processadas e nos devolverá algumas saídas.

Alguns componentes que fazem parte da estrutura de um algoritmo são:

Constantes as informações (dados) que não variam com o tempo, ou seja, permanecem sempre com o mesmo conteúdo, é um valor fixo (invariável). Como exemplos de constantes pode-se citar: números, letras, palavras etc.

Variáveis é um espaço da memória do computador que "reservamos" para guardar informações (dados). Como o próprio nome sugere, as variáveis, podem conter valores diferentes a cada instante de tempo, ou seja, seu conteúdo pode variar de acordo com as instruções do algoritmo.

Tipos, declara se um numero é inteiro, ex: 1 ou 100, fracionário ex: ½ ou 1/10, entre outros.

Operadores Aritméticos

Muitas vezes, ao desenvolvermos algoritmos, é comum utilizarmos expressões matemáticas para a resolução de cálculos. Exemplo:Multiplicação (Produto) *Divisão /Adição (Soma) +Subtração (Diferença) -(Existem também operadores lógicos e Relacionais, seguem a mesma regra)

Palavras-Chave são ordens ou rotinas que fazem parte da linguagem, Exemplo:LeiaPareEscrevaRepita

Ponteiro é uma objeto cujo valor se refere diretamente a (ou "aponta para"), outro valor armazenado em outras partes do usando seu endereço. Para linguagens de programação de alto nível, os ponteiros efetivamente tomar o lugar de registros de uso geral. Como uma analogia, um número de página no índice de um livro poderia ser considerado um ponteiro para a página correspondente; tal ponteiro seria feito lançando para a página com o número da página dada.

Array ou Array, também conhecido como vetor (para arrays unidimensionais) ou array (para arrays bidimensionais), é uma das mais simples estruturas de dados. Os arrays mantêm uma série de elementos de dados, geralmente do mesmo tamanho e tipo de dados. Os arrays podem ser considerados como as estruturas de dados mais simples.

Slice é uma notação que retorna um pedaço/slice de uma string ou outro.

VISITE UMA IGREJA EVANGELICA

Page 27: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Struct (em português Estrutura) é uma declaração que define uma lista de variáveis a serem colocados sob o mesmo nome em um bloco de memória, permitindo que as diferentes variáveis para ser acessado através de um único ponteiro.

String (ou cadeia de caracteres) é um vetor de caracteres, utilizada para o armazenamento de texto.

Aprendendo a Estudar Programação.

Nos dias que correm, não saber trabalhar com computadores é considerada iliteracia (analfabetismo) e o custo por não saber utilizar um computador pode ser caro. Quando usamos computadores, podemos fazer muitas coisas. Uma criança pode usar a Internet para passar uma mensagem, um estudante pode usar uma planilha eletrônica para calcular uma média ou quantos pontos precisa para ser aprovado em cada matéria, um cozinheiro pode guardar suas receitas em software como o Word ou em um produto especializado para receitas. Na verdade, a quantidade de produtos especializados é tão grande que, se você procurar bem, certamente vai encontrar algum programa que faça algo bem próximo do que você deseja.

O problema é que, às vezes, queremos fazer algo específico: queremos um programa de computador que faça algo que servirá de forma única a nós ou a nossa empresa. Nesse caso, em vez de comprar um programa pronto temos que desenvolver o nosso próprio programa. Para isso é necessário dominar uma nova forma de manipular o computador: a programação. Nosso motivo pode ser um negócio, um trabalho escolar, um hobby ou mera curiosidade. Hoje em dia, programar um computador pode ser feito de várias formas. Você pode, por exemplo, modificar levemente o comportamento de aplicações por meio de macros, como é permitido em programas como Microsoft Word. Você pode fazer ainda modificações mais sérias por meio de linguagens embutidas, como pode ser feito também nos programas do Microsoft Office ou até mesmo em jogos de computador como Neverwinter Nights. Você pode também pegar um programa já existente de código aberto, ou software livre e modificá-lo. Ou você pode começar do início e programar praticamente tudo, certamente com ajuda de bibliotecas prontas que fazem parte do trabalho.

Para programar você tem muitas opções: pacotes que podem ser estendidos com macros ou linguagens embutidas, ambientes de programação point-and-click, linguagens mais fáceis de aprender e linguagens mais difíceis, mas que apresentam grande poder ou características apropriadas para grandes sistemas. Em todo caso, o espírito por trás de tudo é o mesmo: programar é dar ordens para o computador, mostrar como ele deve reagir ao usuário e como ele deve processar os dados disponíveis.

Praticamente não há limite do que você pode fazer com um computador. Computadores ajudam pessoas a falar, controlam aparelhos e levaram o homem à Lua de várias maneiras. Mesmo as coisas mais difíceis, como simular um sentimento ou inteligência, são estudadas com afinco em todo mundo. Alguns problemas são muito grandes e exigem a construção de computadores enormes. Outros são tão simples que podemos resolver em computadores simples, que estão dentro de equipamentos. Hoje é difícil imaginar um domínio da atividade humana onde a utilização de computadores não seja desejável. Assim sendo o domínio da programação é substancialmente ditado pela imaginação e criatividade. Podemos dizer que a grande vantagem de saber programar é a possibilidade de criar o que quiser, quando quiser. Não só para o PC, mas celulares, PDAs, entre outros. Claro que exige um pouco de esforço, porém para muitos esse esforço é na verdade um desafio cuja a recompensa é ver sua ideia transformada em realidade.

Quando se pretende estudar uma linguagem, não se pode estar à espera que lendo determinado livro ou frequentando determinado curso ficaremos a sabê-la perfeitamente. A verdade é que não necessitamos do livro para aprender a programar bem e o curso, para alguns, é só uma perda de tempo. A grande maioria dos livros serve como um auxílio ao estudo e não como um suporte base do estudo. Assim, o que a maior parte dos programadores fazem para aprender uma nova linguagem é:

1ª - Estudar a sintaxe da linguagem através de um livro ou manual. 2ª - Entender as diferenças desta linguagem para outras que já saibam - Isto é muito importante! 3ª - Fazer algo que vai realmente torná-lo um bom programador dessa linguagem: Ler código já

feito. 4ª - Começar a escrever os seus próprios programas.

É preciso ter em atenção estes passos que são fundamentais. Assim, se não souber o que é determinada função, sempre pode Go ao manual e procurar. Não se prenda ao "marranço" do livro porque isso não o leva a nada.

Este padrão é eficaz porque, para um iniciante, é possível aprender-se uma linguagem em pouco

VISITE UMA IGREJA EVANGELICA

Page 28: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

mais de 5 ou 6 meses. Para um programador experiente basta apenas uma a duas semanas para cessar a aprendizagem de uma nova linguagem.

Após a passagem por essa linguagem, inscreva-se numa das centenas de listas existentes na internet e aperfeiçoe os seus conhecimentos ajudando outros usuários a criar programas open source. Verá que se sentirá feliz por ter chegado tão longe! É necessário ter em mente que se seguir estas regras aprenderá a ser um bom programador.

Método para desenvolvimento de algoritmos

1. Faça uma leitura de todo o problema até o estreitol, a fim de formar a primeira impressão. A seguir, releia o problema e faça anotações sobre os pontos principais.

2. Verifique se o problema foi bem entendido. Questione, se preciso, ao autor da especificação sobre suas dúvidas. Releia o problema quantas vezes for preciso para tentar entendê-lo.

3. Extraia do problema todas as suas saídas.

4. Extraia do problema todas as suas entradas.

5. Identifique qual é o processamento principal.

6. Verifique se será necessário algum valor intermediário que auxilie a transformação das entradas em saídas. Esta etapa pode parecer obscura no início, mas com certeza no desenrolar do algoritmo, estes valores aparecerão naturalmente.

7. Teste cada passo do algoritmo, com todos os seus caminhos para verificar se o processamento está gerando os resultados esperados.

Crie valores de teste para submeter ao algoritmo.

8. Reveja o algoritmo, checando as boas normas de criação.

Conselho: Só tente conseguir o ótimo, depois de realizar o bom.

Dicas para iniciantes apreenderem programação.

1º – Todo programador tem que saber lógica de programação, não existe programador sem lógica.

2º – Ninguém quer te ajudar, a não ser que a pessoa que você pediu ajuda ganhe algo com isso. As pessoas já tem problemas demais para ficar resolvendo os seus.

3º – Você sempre será um estudante. Sempre tem algo à aprender.

4º – Você não é pior que ninguém, e ninguém é melhor que você. Todos nós somos inteligentes, ninguém é “burro”. Apenas algumas pessoas são mais estudadas que você.

5º – Você não tem que gostar de ler, mais também não pode odiar. Você pode não gostar de ler um livro com tema amoroso, ou dramático, mas um livro sobre programação (Que é o que você estuda) você tem que gostar. Se não gostar… porque está tentando aprender à programar?

6º – Qual é seu objetivo? Aprender à programar ou criar um keylogger? Ou um Trojan? Ou um chat para trapacear um jogo? Se quer mesmo aprender a programar dedique à aprender e não à seguir tutoriais com códigos prontos e copiar e colar sem saber o que faz.

7º – Se você acha que está muito difícil aprender a programar, calma, descanse depois volte aos estudos e leia novamente, tente entender. Se você acha que não consegue mesmo, tire isso da sua cabeça, em si já é uma barreira.

VISITE UMA IGREJA EVANGELICA

Page 29: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

8º – Comece do começo, pra que vai tentar aprender uma coisa avançada se você não sabe nem o básico? Um bom exemplo para isso é a escola, pra que um professor vai ensinar figuras de linguagem aos alunos se eles não sabem nem ler? Tentar aprender pelo avançado de uma vez é perda de tempo.

9º – De início escolha uma linguagem mais simples. Antes de estudar linguagens de baixo e alto nível, eu recomendo você estudar HTML para você se familiarizar com códigos. Logo, recomendo Visual Basic, Pascal, Python, uma destas linguagens para início.

10º – Pesquise, Raciocine !! Use seu cérebro, não peça programas prontos onde você só se dá o trabalho de colocar seus créditos.

Classificação

Pode-se classificar algoritmos pela maneira pelo qual foram implementados.

Recursivo ou iterativo - um algoritmo recursivo possui a característica de invocar a si mesmo repetidamente até que certa condição seja satisfeita e ele é terminado, que é um método comum em programação funcional. Algoritmos iterativos usam estruturas de repetição tais como laços, ou ainda estruturas de dados adicionais tais como pilhas, para resolver problemas. Cada algoritmo recursivo possui um algoritmo iterativo equivalente e vice-versa, mas que pode ter mais ou menos complexidade em sua construção.

Lógico - um algoritmo pode ser visto como uma dedução lógica controlada. O componente lógico expressa os axiomas usados na computação e o componente de controle determina a maneira como a dedução é aplicada aos axiomas. Tal conceito é base para a programação lógica.

Serial ou paralelo - algoritmos são geralmente assumidos por serem executados instrução a instrução individualmente, como uma lista de execução, o que constitui um algoritmo serial. Tal conceito é base para a programação imperativa. Por outro lado existem algoritmos executados paralelamente, que levam em conta as arquiteturas de computadores com mais de um processador para executar mais de uma instrução ao mesmo tempo. Tais algoritmos dividem os problemas em subproblemas e o delegam a quantos processadores estiverem disponíveis, agrupando no estreitol o resultado dos subproblemas em um resultado estreitol ao algoritmo. Tal conceito é base para a programação paralela. De forma geral, algoritmos iterativos são paralelizáveis; por outro lado existem algoritmos que não são paralelizáveis, chamados então problemas inerentemente seriais.

Determinístico ou não-determinístico - algoritmos determinísticos resolvem o problema com uma decisão exata a cada passo enquanto algoritmos não-determinísticos resolvem o problema ao deduzir os melhores passos através de estimativas sob forma de heurísticas.

Exato ou aproximado - enquanto alguns algoritmos encontram uma resposta exata, algoritmos de aproximação procuram uma resposta próxima a verdadeira solução, seja através de estratégia determinística ou aleatória. Possuem aplicações práticas sobretudo para problemas muito complexos, do qual uma resposta correta é inviável devido à sua complexidade computacional.

Classificação por paradigma

Pode-se classificar algoritmos pela metodologia ou paradigma de seu desenvolvimento, tais como:

Divisão e conquista - algoritmos de divisão e conquista reduzem repetidamente o problema em subproblemas, geralmente de forma recursiva, até que o subproblema é pequeno o suficiente para ser resolvido. Um exemplo prático é o algoritmo de ordenação merge sort. Uma variante dessa metodologia é o decremento e conquista, que resolve um subproblema e utiliza a solução para resolver um problema maior. Um exemplo prático é o algoritmo para pesquisa binária.

Programação dinâmica - pode-se utilizar a programação dinâmica para evitar o recálculo de solução já resolvidas anteriormente.

Algoritmo ganancioso - um algoritmo ganancioso é similar à programação dinâmica, mas difere na medida em que as soluções dos subproblemas não precisam ser conhecidas a cada passo, uma escolha gananciosa pode ser feita a cada momento com o que até então parece ser mais adequado.

VISITE UMA IGREJA EVANGELICA

Page 30: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Programação linear Redução - a redução resolve o problema ao transformá-lo em outro problema. É chamado também

transformação e conquista. Busca e enumeração - vários problemas podem ser modelados através de grafos. Um algoritmo de

exploração de grafo pode ser usado para caminhar pela estrutura e retornam informações úteis para a resolução do problema. Esta categoria inclui algoritmos de busca e backtracking.

Paradigma heurístico e probabilístico - algoritmos probabilísticos realizam escolhas aleatoriamente. Algoritmos genéticos tentam encontrar a solução através de ciclos de mutações evolucionárias entre gerações de passos, tendendo para a solução exata do problema. Algoritmos heurísticos encontram uma solução aproximada para o problema.

Classificação por campo de estudo

Cada campo da ciência possui seus próprios problemas e respectivos algoritmos adequados para resolvê-los. Exemplos clássicos são algoritmos de busca, de ordenação, de análise numérica, de teoria de grafos, de manipulação de cadeias de texto, de geometria computacional, de análise combinatória, de aprendizagem de máquina, de criptografia, de compressão de dados e de interpretação de texto.

Classificação por complexidade

Alguns algoritmos são executados em tempo linear, de acordo com a entrada, enquanto outros são executados em tempo exponencial ou até mesmo nunca terminam de serem executados. Alguns problemas tem múltiplos algoritmos enquanto outros não possuem algoritmos para resolução.

Podemos enquadrar os problemas em três grandes grupos:1. Os que não têm solução e portanto não há nada a fazer, que são classificados como problemas indecidíveis

(ou impossíveis de serem solucionados).2. Os que têm solução algorítmica e podemos resolvê-los formalmente passo a passo, codificando os

algoritmos para sua resolução.3. Um terceiro grupo que não pertencem aos dois anteriores. Dentre eles podemos ter: Aqueles em que a solução algorítmica têm complexidade NP-Completa; Aqueles que o Ser Humano é capaz de resolver; Aqueles que os Seres Vivos são capazes de resolver. Ex: Jogar Xadrez, Jogar Futebol, Reconhecer Faces,

Fazer Traduções, Procurar Comida, Reconhecer Letras, entre outros.

Definição de problema

É difícil de explicar precisamente o que é um problema, mas podemos explicar como sendo uma questão que se propõe para ser resolvida. Note que resolver um problema não necessariamente significa em se ter um método para resolvê-lo. Antes mesmo de se tentar buscar a solução de um problema, deve-se responder as seguintes perguntas:

Quais são os dados (informações)? Quais são as soluções possíveis? O que caracteriza uma solução satisfatória?

Também pode-se pensar que problema é algo difícil de resolver, uma dúvida, uma questão, enigma ou mistério. Problema é melhor "entendido" nas diferentes áreas do conhecimento, por exemplo:

Problema dos canibais e missionários; Problema do caixeiro viajante; Problema das pontes de Königsberg; Problema do carteGoo chinês Tabuleiro de xadrez mutilado;

Na Teoria dos problemas um problema pode ser representado em linguagem matemática da seguinte forma:

P = (I, B, C)P: O problema apresentado;B: O conjunto de dados do problema, conjunto não vazio, que deve representar a informação

apropriada do problema. Alguns elementos podem permanecer iguais e outros em constante dinâmica. É necessário documentar não só o estado inicial do problema mas também todos seus estados de mudanças.

VISITE UMA IGREJA EVANGELICA

Page 31: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

I: O conjunto de operações e transformações, também conjunto não vazio, que podem ocorrer durante o processo da resolução do problema desde a sua fase inicial, as possíveis respostas.

C: Condição, uma relação binária, que deve satisfazer o problema. Esta relação caracteriza uma solução satisfatória, ela associa a cada elemento do conjunto de dados a solução única desejada. Mais precisamente é o conjunto solução do problema.

Caracterização de um problema

Uma pessoa que enfrenta um problema para satisfazer certos objetivos e não conhece que ações deve tomar para conseguir resolvê-lo.

Então ao se resolver um problema identificamos os seguintes componentes: Um objetivo para ser alcançado, um conjunto de ações pré-pensadas para resolver tal problema e a situação inicial do tal problema.

Exemplo: Um Puzzle Existe um tabuleiro de 4x4 casas e 15 peças somente. O problema é que temos que fazer com que

as peças espalhadas no quadrado formem uma configuração previamente definida. Existe uma regra para isso, o movimento somente ocorre uma peça por vez e somente para casas adjacentes.

Neste caso o conjunto de dados do problema poderia ser descrito pela configuração das peças no tabuleiro, as operações de busca da solução como movimentos das peças de acordo com as regras, e a configuração estreitol a solução do problema.

Um problema de diagnóstico médico pode ser modelado da mesma maneira, seja:

O problema "P" é o diagnóstico. O conjunto "B" da dados do problema são dados que o médico obteve de exames com seu paciente. O conjunto "C" da solução é o conjunto de todas as doenças possíveis.

Neste caso, a busca de uma solução é encontrar um par (d,k), tal que d B e k C.Em casos como o diagnóstico médico estamos buscando uma função que resolva o problema, essa

função é denominada função problema.

Um outro exemplo, é o problema da raiz de polinômio. A solução do problema da busca das raízes de um polinômio com coeficientes reais consiste em

associar a cada conjunto de coeficientes de um polinômio particular p(x) de grau n, n números complexos cn de modo a satisfazer a condição de que o valor de p(x) fazendo x = c para todo n seja nulo.

A função problema

A função problema, se existir, pode ser encontrada de diversas formas: Enumeração exaustiva: Enumerando todos os pares que ligam dados do problema ao conjunto solução.

Evidentemente, este modo de definir uma função, só se aplica no caso que o conjunto de dados é finito. Exemplo:

Seja uma agenda de telefones. Ela pode ser considerada como a função que associa a cada nome de pessoa seu telefone.

Declarativamente: Definindo propriedades que definem a solução do problema. Exemplo 1:

Dado um número real, associa dois números cuja soma de seus quadrados é igual ao número real dado. A solução pode ser visualizada como um círculo, centrado na origem de um plano com coordenadas ortonormais (eixos ortogonais e de mesma escala), de raio igual ao número dado.

Exemplo 2: Seja a função característica do conjunto das equações diofantinas de quarta ordem que tem solução.

Ora a partir de 3 sabe-se não haver teorema permitindo saber se o problema tem ou não solução. Logo, o

VISITE UMA IGREJA EVANGELICA

Page 32: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

que resta é tentar todas as possibilidades... e como existem infinitos números inteiros não se pode ter certeza, se calculando o problema tem solução ou ainda não foi achada ou não tem solução!

Por um algoritmo: A correspondência entre dados e resultados é feita através de um programa de computador, e sempre que ele para consegue-se chegar a uma solução. Sendo assim, um programa pode ser considerado como um modo de definir um problema.

Exemplo:

Formulário de Imposto de Renda

Pode-se reconhecer que, neste caso, a solução não é única: todas as funções que sejam iguais dentro subconjunto em que o problema é definido são válidas e é necessário fazer uma aproximação, neste caso costuma-se usar técnicas de Inteligência artificial como Rede neural, Usam-se os exemplos para treinar a rede e obtém-se valores estimados da solução para os outros valores usando a propriedade de generalização das redes.

Exemplo:

Costuma-se empregar redes neurais com aprendizado supervisionado. Usam-se os exemplos para treinar a rede e obtém-se valores estimados da solução para os outros valores usando a propriedade de generalização das redes

Para Aprender uma Linguagem

Muitos anos se passaram desde os primórdios da história da computação, mas apesar de já termos vivido vários paradigmas de programação, existe uma base de conhecimento que não mudou e não mudará nunca – a Lógica de Programação.

Faço uma associação direto da Lógica de Programação com o Raciocínio Matemático, onde o importante é a interpretação de um problema e a utilização correta de uma fórmula, e não a sintaxe pré-definida da mesma. O saber da Lógica está no “praticar”.

Não existem “fórmulas” em Informática, o que existe é o aperfeiçoamento de nossa forma de pensar e raciocinar sobre um problema, podendo extrair do mesmo uma solução eficiente e eficaz, sob um determinado ângulo de visão. Assim, verificamos que é preciso aprender a pensar sobre os problemas, extraindo deles o máximo de informações.

A solução que criamos para um determinado problema necessita ser exteriorizada e expressa numa linguagem publicamente conhecida. Assim, utilizamos a lógica de programação para desenvolver nossas soluções e os algoritmos para apresentar essas soluções ao mundo.

Vários livros de Algoritmos e Estruturas de Dados. Todos ensinam como representamos estruturas de controle e atribuições, ou como declaramos variáveis, mas nenhum deles – que eu tenha lido até o momento –, orientou o aluno na forma de pensar. Precisamos mais do que “fórmulas”, precisamos aprender a pensar.

Apresentaremos como desenvolver algoritmos de soluções para Sistemas, vamos conhecer a Linguagem Go do Google, a fim de vermos nossos algoritmos funcionando. Por melhor que seja o conhecimento do Analista/Programador, este só poderá ter certeza que sua “estratégia” foi bem sucedida após testar o programa num computador.

Bons programadores tem poucas surpresas quando testam seus programas, fazendo normalmente umas poucas correções para que o programa funcione de maneira adequada. Programadores iniciantes criam uma estratégia (algoritmo) muitas vezes ineficiente não é raro ouvirmos de iniciantes a frase “Nunca conseguirei fazer um programa ...”. Certamente, não conseguirá mesmo, caso não tenha uma estratégia definida.

Imagine uma “tarefa” muito simples, como por exemplo fritar um ovo. Caso você não soubesse “operar” o fogão provavelmente não conseguiria acendê-lo. Se nunca tivesse visto alguém quebrar um ovo, provavelmente não conseguiria fazê-lo sem perder parte de seu conteúdo. A fritura seria algo desastroso, caso você desconhecesse a utilidade do óleo. E o sabor seria frustrante, caso o tempero utilizado fosse açúcar.

O Programador iniciante que não simula seu algoritmo, se compara ao cozinheiro desastrado descrito acima. E como simular? Basta “agirmos” como se fossemos o próprio computador, ou seja devemos “fingir” que nosso raciocínio é baseado no conteúdo de variáveis. De fato, usualmente antes de tomarmos alguma

VISITE UMA IGREJA EVANGELICA

Page 33: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

decisão analisamos uma série de fatores (as tais variáveis dos programas). Desta forma, caso fizermos uma análise apurada sobre os conteúdos das variáveis, poderemos “descobrir” a função de cada programa.

Devemos entender Nível Alto como sendo a capacidade da linguagem em compreender instruções escritas em “dialetos” próximos do inglês (Ada e Pascal, por exemplo) e Nível Baixo para aquelas linguagens que se aproximam do assembly, que é a linguagem própria da máquina, compostas por instruções binárias e outras incompreensíveis para o ser humano não treinado para este propósito. Infelizmente, quanto mais clara uma linguagem for para o humano (simplicidade >) mais obscura o será para a máquina (velocidade <). Qual linguagem escolherei?

Solução:

Características Ideais Classe ValorExecutáveis Curtos Não Importa 0Executáveis Rápidos Fundamental 3Portáveis Desejável 1Simplicidade Desejável 1Manipulação de Bits Necessário 2

0- Não Importa 1- Desejável 2- Necessário 3- Fundamental

CONCEITOS GERAIS DE PROGRAMAÇÃO ESTRUTURADA

A Programação Estruturada pode ser entendida como uma forma de programar que visa facilitar a escrita, entendimento, validação e manutenção de programas. Para “a arte de programar consiste na arte de organizar e dominar a complexidade”.

A Programação Estruturada procurar reduzir o nível de complexidade através de três níveis:a) desenvolvimento do programa em diferentes fases por reestreitomento sucessivo (desenvolvimento

top-down);b) decomposição do programa total em módulos funcionais, organizados de preferência num sistema

hierárquico;c) uso de um número limitado de estruturas básicas de fluxo de controle dentro de cada módulo.

DESENVOLVIMENTO TOP-DOWN

Na Programação Estruturada, ao desenvolvermos um algoritmo, temos como objeto um produto estreitol – o programa. Todavia, para termos esta transição, passamos por várias fases, no sentido “cima para baixo”, onde cada fase é documentada e principalmente obtida por “reestreitomento” da fase anterior, até chegarmos a um nível de detalhamento que permita implementar o algoritmo diretamente na linguagem de programação.

MODULARIZAÇÃO

A solução estreitol de um problema é obtida através de soluções de subproblemas, o que permite dividir o programa em módulos com subjunções claramente delimitadas, que podem, inclusive, ser implementados separadamente, por diversos programadores de uma equipe.

ESTRUTURAS DE CONTROLE

São representadas pela sequência simples, o comando condicional e o comando repetitivo, e fornecem ao programador um aumento da legibilidade e compreensão de cada módulo de programa. Assim, temos como uma das principais normas da Programação Estruturada.

CONFIABILIDADE

VISITE UMA IGREJA EVANGELICA

Page 34: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Medimos a confiabilidade de um sistema através de sua resposta ao uso:- não apresentar erros; e,- corresponder às especificações.Atualmente, a sociedade está totalmente dependente dos sistemas de computação. Assim, aumenta

exponencialmente a importância do nosso trabalho.Nos fins dos anos 60, constatou-se que as sistemáticas usadas pelos programadores eram os grandes

responsáveis pela baixa confiabilidade dos programas.Como solução destes problemas, surgiu a Programação Estruturada (PE). MANUTENIBILIDADE

As revisões sofridas por um programa (releases) tanto para correção de erros quanto para mudanças de especificação, são consideradas como manutenção de software.

Os programas devem passar por testes exaustivos de confiabilidade antes de serem colocados em produção. Falhas nesta fase levam a altos níveis de manutenção, que consequentemente, levam a altos custos.

PROGRAMAÇÃO CONCORRENTE

A programação concorrente foi usada inicialmente na construção de sistemas operacionais. Atualmente, ela é usada para desenvolver aplicações em todas as áreas da computação. Este tipo de programação tornou-se ainda mais importante com o advento dos sistemas distribuídos e das máquinas com arquitetura paralela. A linguagem Go faz concorrência, paralelismo e coleta de lixo automaticamente reduzindo as chances de erro e deixando o programador mais à vontade para pensar na elaboração do código fonte, mais você vai precisar da lógica apresentada para construir seus algoritmos, estrutura do programa ou interação com o sistema. A lógica apresentada nesse capitulo ilustra um tipo rede e de comunicação entre processos.

A grande maioria dos programas escritos são programas sequenciais. Nesse caso, existe somente um fluxo de controle (fluxo de execução, linha de execução, thread) no programa. Isso permite, por exemplo, que o programador realize uma "execução imaginária" de seu programa apontando, a cada instante, o comando que está sendo executada no momento. Enquanto um programa concorrente pode ser visto como se tivesse vários fluxos de execução. Para o programador realizar agora uma "execução imaginária", ele vai necessitar de vários dedos, um para cada fluxo de controle.

O termo "programação concorrente" significa "acontecendo ao mesmo tempo”. É comum em sistemas multiusuário que um mesmo programa seja executado simultaneamente por vários usuários. Por exemplo, um editor de texto. Entretanto, ter 10 execuções simultâneas do editor de texto não faz dele um programa concorrente. O que se tem são 10 processos independentes executando o mesmo programa sequencial (compartilhando o mesmo código). Cada processo tem a sua área de dados e ignora a existência das outras execuções do programa. Esses processos não interagem entre si (não trocam informações). Um programa é considerado concorrente quando ele (o próprio programa, durante a sua execução) origina diferentes processos. Esses processos, em geral, irão interagir entre si.

A programação concorrente é mais complexa que a programação sequencial. Um programa concorrente pode apresentar todos os tipos de erros que aparecem nos programas sequenciais e, adicionalmente, os erros associados com as interações entre os processos. Muitos erros dependem do exato instante de tempo em que o escalonador do sistema operacional realiza um chaveamento de contexto. Isso torna muitos erros difíceis de reproduzir e de identificar.

Apesar da maior complexidade, existem muitas áreas nas quais a programação concorrente é vantajosa. Em sistemas nos quais existem vários processadores (máquinas paralelas ou sistemas distribuídos), é possível aproveitar esse paralelismo e acelerar a execução do programa. Mesmo em sistemas com um único processador, existem razões para o seu uso em vários tipos de aplicações.

Considere um programa que deve ler registros de um arquivo, colocar em um formato apropriado e então enviar para uma impressora física (em oposição a uma impressora lógica ou virtual, implementada com arquivos). Podemos fazer isso com um programa sequencial que, dentro de um laço, faz as três operações (ler, formatar e imprimir registro).

Inicialmente o processo envia um comando para a leitura do arquivo e fica bloqueado. O disco então é acionado para realizar a operação de leitura. Uma vez concluída a leitura, o processo realiza a formatação e inicia a transferência dos dados para a impressora. Como trata-se de uma impressora física, o processo executa um laço no qual os dados são enviados para a porta serial ou paralela apropriada. Como o buffer

VISITE UMA IGREJA EVANGELICA

Page 35: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

da impressora é relativamente pequeno, o processo fica preso até o estreitol da impressão. O disco e a impressora nunca trabalham simultaneamente, embora isso seja possível. É o programa sequencial que não consegue ocupar ambos.

Vamos agora considerar um programa concorrente como o mostrado na figura 2 para realizar a impressão do arquivo. Dois processos dividem o trabalho. O processo leitor é responsável por ler registros do arquivo, formatar e colocar em um buffer na memória. O processo impressor retira os dados do buffer e envia para a impressora. É suposto aqui que os dois processos possuem acesso à memória onde está o buffer. Este programa é mais eficiente, pois consegue manter o disco e a impressora trabalhando simultaneamente. O tempo total para realizar a impressão do arquivo vai ser menor.

O uso da programação concorrente é natural nas aplicações que apresentam paralelismo intrínseco, ditas aplicações inerentemente paralelas. Nessas aplicações pode-se distinguir facilmente funções para serem realizadas em paralelo. Este é o caso do spooling de impressão, exemplo que será apresentado a seguir. Pode-se dizer que, em geral, a programação concorrente tem aplicação natural na construção de sistemas que tenham de implementar serviços que são requisitados de forma imprevisível [DIJ65]. Nesse caso, o programa concorrente terá um processo para realizar cada tipo de serviço.

A seguir é considerado um servidor de impressão para uma rede local. A figura 3 ilustra uma rede local na qual existem diversos computadores pessoais (PC) utilizados pelos usuários e existe um computador dedicado ao papel de servidor de impressão. O servidor usa um disco magnético para manter os arquivos que estão na fila de impressão.

É importante observar que o programa "servidor de impressão" possui paralelismo intrínseco. Ele deve: (1) receber mensagens pela rede; (2) escrever em disco os pedaços de arquivos recebidos; (3) enviar mensagens pela rede (contendo, por exemplo, respostas às consultas sobre o seu estado); (4) ler arquivos previamente recebidos (para imprimi-los); (5) enviar dados para a impressora. Todas essas atividades podem ser realizadas "simultaneamente". Uma forma de programar o servidor de impressão é usar vários processos, cada um responsável por uma atividade em particular. Obviamente, esses processos vão precisar trocar informações para realizar o seu trabalho.

A figura 4 mostra uma das possíveis soluções para a organização interna do programa concorrente "servidor de impressão". Cada círculo representa um processo. Cada flecha representa a passagem de dados de um processo para o outro. Essa passagem de dados pode ser feita, por exemplo, através de variáveis que são compartilhadas pelos processos envolvidos na comunicação.

Vamos agora descrever a função de cada processo. O processo "Receptor" é responsável por receber mensagens da rede local. Ele faz isso através de chamadas de sistema apropriadas e descarta as mensagens com erro. As mensagens corretas são então passadas para o processo "Protocolo". Ele analisa o conteúdo das mensagens recebidas à luz do protocolo de comunicação suportado pelo servidor de impressão. É possível que seja necessário a geração e o envio de mensagens de resposta. O processo "Protocolo" gera as mensagens a serem enviadas e passa-as para o processo "Transmissor", que as envia através de chamadas de sistema apropriadas.

Algumas mensagens contêm pedaços de arquivos a serem impressos. É suposto aqui que o tamanho das mensagens tenha um limite (alguns Kbytes). Dessa forma, um arquivo deve ser dividido em várias mensagens para transmissão através da rede. Quando o processo "Protocolo" identifica uma mensagem que contém um pedaço de arquivo, ele passa esse pedaço de arquivo para o processo "Escritor". Passa também a identificação do arquivo ao qual o pedaço em questão pertence. Cabe ao processo "Escritor" usar as chamadas de sistema apropriadas para escrever no disco. Quando o pedaço de arquivo em questão é o último de seu arquivo, o processo "Escritor" passa para o processo "Leitor" o nome do arquivo, que está pronto para ser impresso.

O processo "Leitor" executa um laço no qual ele pega um nome de arquivo, envia o conteúdo do arquivo para o processo "Impressor" e então remove o arquivo lido. O envio do conteúdo para o processo "Impressor" é feito através de um laço interno composto pela leitura de uma parte do arquivo e pelo envio dessa parte. Estreitamente, o processo "Impressor" é encarregado de enviar os pedaços de arquivo que ele recebe para a impressora. O relacionamento entre os processos "Leitor" e "Escritor" foi descrito antes, no início desta seção.

O servidor de impressão ilustra o emprego da programação concorrente na construção de uma aplicação com paralelismo intrínseco. O resultado é uma organização interna clara e simples para o programa. Um programa sequencial equivalente seria certamente menos eficiente. O restante deste capítulo é dedicado aos problemas e às técnicas existentes para a construção de programas concorrentes como esse.

Hoje em dia existem várias linguagens que permitem construir programas concorrentes (Java, Ada, Pascal Concorrente, C estendido com bibliotecas para concorrência, etc.). Aqui será utilizada uma linguagem apropriada para ensino, denominada Vale4.

Sincronizações básicas

VISITE UMA IGREJA EVANGELICA

Page 36: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

O que melhor distingue uma thread de um processo é o espaço de endereçamento. Todas as threads de um processo trabalham no mesmo espaço de endereçamento, que é a memória lógica do “processo hospedeiro”. Isto é, quando se tem um conjunto de threads dentro de um processo, todas as threads executam o código do processo e compartilham as suas variáveis. Por outro lado, quando se tem um conjunto de processos, cada processo trabalha num espaço de endereçamento próprio, com um conjunto separado de variáveis.

No caso de um processo com N threads, tem-se um único registro descritor (o registro do processo hospedeiro) e N mini descritores de threads. O mini descritor de cada thread é usado para salvar os valores dos registradores da UCP (PC, PSW, etc.). Adicionalmente, cada thread possui uma pilha, que é usada para as chamadas e retornos de procedimentos.

É mais fácil chavear a execução entre threads (de um mesmo processo) do que entre processos, pois tem-se menos informações para salvar e restaurar. Por esse motivo, as threads são chamadas também de "processos leves".

É comum um processo ter que esperar até que uma condição se torne verdadeira. Para essa espera ser "eficiente", o processo deve esperar no estado bloqueado (sem competir pela UCP). Dois tipos de bloqueio são considerados básicos:

1. Bloquear até que um recurso se torne disponível;1

2. Bloquear até que chegue um sinal de outro processo.

Programas clássicos

Esta seção apresenta 4 problemas clássicos da programação concorrente, todos resolvidos através do uso de semáforos e todos escritos de acordo com a sintaxe de Vale4.

Produtor-consumidor com buffer limitado

Este problema pode ser enunciado como segue. Um par de processos compartilha um buffer de N posições. O primeiro processo, denominado produtor, passa a vida a produzir mensagens e a colocá-las no buffer. O segundo processo, denominado consumidor, passa a vida a retirar mensagens do buffer (na mesma ordem em que elas foram colocadas) e a consumi-las.

A relação produtor-consumidor ocorre comumente em sistemas concorrentes e o problema se resume em administrar o buffer que tem tamanho limitado. Se o buffer está cheio, o produtor deve se bloquear, se o buffer está vazio, o consumidor deve se bloquear. A programação desse sistema com buffer de 5 posições e supondo que as mensagens sejam números inteiros.

Jantar dos Filósofos

Este problema ilustra as situações de deadlock e de postergação indefinida que podem ocorrer em sistemas nos quais processos adquirem e liberam recursos continuamente.

Existem N filósofos que passam suas vidas pensando e comendo. Cada um possui seu lugar numa mesa circular, em cujo centro há um grande prato de spaghetti. A figura 6 ilustra a situação para 5 filósofos. Como a massa é muito escorregadia, ela requer dois garfos para ser comida. Na mesa existem N garfos, um entre cada dois filósofos, e os únicos garfos que um filósofo pode usar são os dois que lhe correspondem (o da sua esquerda e o da sua direita). O problema consiste em simular o comportamento dos filósofos procurando evitar situações de deadlock (bloqueio permanente) e de postergação indefinida (bloqueio por tempo indefinido).

Da definição do problema, tem-se que nunca dois filósofos adjacentes poderão comer ao mesmo tempo e que, no máximo, N/2 filósofos poderão estar comendo de cada vez. Na solução a seguir, iremos nos concentrar no caso de 5 filósofos. Os garfos são representados por um vetor de semáforos e é adotada a seguinte regra: todos os 5 filósofos pegam primeiro o seu garfo da esquerda, depois o da direita, com exceção de um deles, que é do contra. Pode ser demonstrado que esta solução é livre de deadlocks. Foi escolhido o filósofo 1 para ser do contra.

Barbeiro dorminhoco

1

VISITE UMA IGREJA EVANGELICA

Page 37: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

O problema consiste em simular o funcionamento de uma barbearia com as seguintes características. A barbearia tem uma sala de espera com N cadeiras e uma cadeira de barbear. Se não tem clientes à espera, o barbeiro senta numa cadeira e dorme. Quando chega um cliente, ele acorda o barbeiro. Se chega outro cliente enquanto o barbeiro está trabalhando, ele ocupa uma cadeira e espera (se tem alguma cadeira disponível) ou vai embora (se todas as cadeiras estão ocupadas).

A solução a seguir usa 3 semáforos: clientes, fila e mutex. O semáforo clientes tranca o barbeiro, sendo suas “bolotas” produzidas pelos clientes que chegam. O valor desse semáforo indica o número de clientes à espera (excluindo o cliente na cadeira do barbeiro, que não está à espera). O semáforo fila tranca os clientes e implementa a fila de espera. O semáforo mutex garante exclusão mútua. Também é usada uma variável inteira, count, que conta o número de clientes à espera. O valor desta variável é sempre igual ao “número de bolotas” do semáforo clientes.

Um cliente que chega na barbearia verifica o número de clientes à espera. Se esse número é menor que o número de cadeiras, o cliente espera, caso contrário, ele vai embora. A solução é apresentada a seguir, considerando o número de cadeiras na sala de espera igual a 3.

Inicialmente, o barbeiro executa a operação P(clientes), onde fica bloqueado (dormindo) até a chegada de algum cliente. Quando chega um cliente, ele começa adquirindo a exclusão mútua. Outro cliente que chegar imediatamente após, irá se bloquear até que o primeiro libere a exclusão mútua. Dentro da região crítica, o cliente verifica se o número de pessoas à espera é menor ou igual ao número de cadeiras. Se não é, ele libera mutex e vai embora sem cortar o cabelo.

Se tem alguma cadeira disponível, o cliente incrementa a variável count e executa a operação V no semáforo clientes. Se o barbeiro está dormindo, ele é acordado; caso contrário, é adicionada uma “bolota” no semáforo clientes. A seguir, o cliente libera a exclusão mútua e entra na fila de espera. O barbeiro adquire a exclusão mútua, decrementa o número de clientes, pega o primeiro da fila de espera e vai fazer o corte. Quando termina o corte de cabelo, o cliente deixa a barbearia e o barbeiro repete o seu loop onde tenta pegar um próximo cliente. Se tem cliente, o barbeiro faz outro corte. Se não tem, o barbeiro dorme.

Leitores e escritores

O problema dos readers and writers ilustra outra situação comum em sistemas de processos concorrentes. Este problema surge quando processos executam operações de leitura e de atualização sobre um arquivo global (ou sobre uma estrutura de dados global). A sincronização deve ser tal que vários readers (isto é, processos leitores, que não alteram a informação) possam utilizar o arquivo simultaneamente. Entretanto, qualquer processo writer deve ter acesso exclusivo ao arquivo.

Na solução a seguir é dada prioridade para os processos readers. São utilizadas duas variáveis semáforas, mutex e w, para exclusão mútua, e uma variável inteira nr, para contar o número de processos leitores ativos. Note que o primeiro reader bloqueia o progresso dos writers que chegam após ele, através do semáforo w. Enquanto houver reader ativo, os writers ficarão bloqueados.

VISITE UMA IGREJA EVANGELICA

Page 38: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

PROGRAMANDO EM REDE COM A LINGUAGEM GO

PROGRAMANDO EM REDE NA LINGUAGEM GOLANG

Este capítulo aborda as principais características arquitetônicas de systems distribuídos.

1.1 Introdução

Você não pode construir um sistema sem uma ideia do que você quer construir e se você não conhecer o ambiente em que ele vai trabalhar. Programas gráficos são diferentes de programas de processamento em lote, programas de jogos são diferentes de programas de negócios e programas distribuídos são diferentes de programas independentes. Cada um tem as suas abordagens, seus padrões comuns, o problemas que normalmente surgem e as soluções que são frequentemente utilizados.

Este capítulo aborda os aspectos arquitetônicos Highl evel de sistemas distribuídos. Há muitas maneiras de olhar para tais sistemas, e muitos deles são tratados.

Camadas de protocolo

Sistemas distribuídos são difíceis. Existem vários computadores envolvidos, que têm de ser ligados de alguma forma. Os programas têm de ser escrito para ser executado em cada computador no sistema e todos eles têm de cooperar para começar uma tarefa feita distribuída.

A forma mais comum de lidar com a complexidade é dividi-la em partes menores e mais simples. Estas peças têm a sua própria estrutura, mas eles também têm definido meios de comunicação com outras partes relacionadas. Em sistemas distribuídos, as partes são chamados protocolo camadas e têm funções claramente definidos. Eles formam uma pilha, com cada camada de comunicação com a camada superior e a camada abaixo. A comunicação entre as camadas é definida por protocolos.

Rede de comunicações requer protocolos de comunicação para cobrir aplicação de alto nível, todo o caminho para o fio de comunicação e a complexidade tratadas por encapsulação em camadas de protocolo.

ISO OSI Protocolo

Embora nunca foi devidamente implementado, o protocolo OSI (Open Systems Interconnect) foi uma grande influência na forma de falar e influenciar design de sistemas distribuídos. É comumente dado na figura a seguir:

Camadas OSI

A função de cada uma das camadas é a seguinte:

Camada de rede fornece tecnologias de comutação e roteamento Camada de transporte fornece transferência transparente de dados entre sistemas estreitos e é

VISITE UMA IGREJA EVANGELICA

Page 39: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

responsável por endtoend recuperação de erros e controle de fluxo Camada de sessão estabelece, gerencia e termina conexões entre aplicações. Camada de apresentação fornece independência de diferenças na representação de dados (por

exemplo, criptografia) Camada de aplicação suporta os processos de aplicação e do usuário estreitol

Protocolo TCP / IP

Enquanto o modelo OSI estava sendo discutido, debatido, parcialmente implementado e disputada, o projeto de pesquisa internet DARPA foram ocupados construindo os protocolos TCP / IP. Estes têm sido imensamente bem sucedido. Este é um pilha muito mais simples:

Alguns protocolos alternativosEmbora quase parece que, os protocolos TCP / IP não são os únicos na existência e no longo prazo,

não pode mesmo ser o mais bem sucedido. Existem muitos protocolos ocupando nichos significativos, tais como:

FirewGoe USB Bluetooth WiFi

O foco deste livro será sobre o TCP / IP, mas você deve estar ciente dessas outras.

Networking

Uma rede é um sistema de comunicações para conectar sistemas estreitos chamados hosts. Os mecanismos de conexão pode ser de fio de cobre, eternet, fibra óptica ou wireless, mas isso não nos interessa aqui. Uma rede de área local (LAN) conecta computadores que são juntas, normalmente pertencente a uma casa, pequena organização ou parte de uma organização maior.

A Wide Area Network (WAN) conecta computadores em uma área física maior, como entre as cidades. Existem outros tipos como bem, como MANs (Metropolitan Area Network), PANs (Personal Network) e entre outras.

Uma internet é uma conexão de duas ou mais redes distintas, tipicamente LANs ou WANs. Uma intranet é uma internet com todas as redes pertencente a uma única organização.

Existem diferenças significativas entre uma internet e intranet. Normalmente uma intranet estarão sob uma única administração controle, que Irá impor um único conjunto de políticas coerentes. Uma internet, por outro lado não estar sob o controle de uma única corpo, e os controles exercidos sobre diferentes partes não pode mesmo ser compatível.

Um exemplo trivial de tais diferenças é que uma intranet, muitas vezes, ser restringido a computadores por um pequeno número de fornecedores que executam um versão padronizada de um determinado sistema operacional. Por outro lado, uma internet, muitas vezes, têm um smorgasborg de diferente computadores e sistemas operacionais.

As técnicas deste livro será aplicável a internets. Eles também serão válidos para intranets, mas lá

VISITE UMA IGREJA EVANGELICA

Page 40: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

você também vai encontrar sistemas especializados, não portáteis.E depois há a "mãe" de todas as internets: A Internet. Este é apenas um muito, muito grande na

internet que nos conecta com o Google, o meu computador para o seu computador e assim por diante.

Gateways

Um gateway é um termo genérico para uma entidade utilizada para ligar duas ou mais redes. Um repetidor opera para as cópias de nível físico a informação de uma sub-rede para outra. Uma ponte opera no nível da camada de enlace de dados e cópias de quadros entre as redes. A router opera no nível de rede, e não só se move informações entre redes, mas também decide sobre a rota.

Packet encapsulamento

A comunicação entre as camadas em ambos os OSI ou as pilhas de TCP / IP é feito pelo envio de pacotes de dados a partir de uma camada de a próxima, e depois, eventualmente, através da rede. Cada camada tem informações administrativas que ele tem de manter sobre sua própria camada.

Ele faz isso através da adição de informações de cabeçalho do pacote que recebe da camada superior, como o pacote passa para baixo. No receber lado, estes cabeçalhos são removidas como o pacote se move para cima.

Por exemplo, a TFP (Trivial File Transfer Protocol) move arquivos de um computador para outro. Ele utiliza o protocolo UDP no topo o protocolo de IP, que pode ser enviado através de Ethernet. Isso se parece com:

O pacote transmitido over ethernet, é claro, a um fundo.

Modelos de conexão

Para que dois computadores se comuniquem, eles devem estabelecer um caminho pelo qual eles podem enviar pelo menos uma mensagem em uma sessão.

Existem dois modelos principais para isso:

Conexão orientada Sem conexão

Conexão orientada

A única conexão é estabelecida para a sessão. Comunicações bidirecionais fluir ao longo da conexão. Quando a sessão acabou, a conexão é quebrada. A analogia é uma conversa por telefone. Um exemplo é o TCP.

Sem conexão

VISITE UMA IGREJA EVANGELICA

Page 41: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Em um sistema de conexão, as mensagens são enviadas independente um do outro. O correio normal é a analogia. Mensagens sem conexão podem chegar fora de ordem. Um exemplo é o protocolo IP. Transportes orientados conexão pode ser estabelecida em cima de conexão queridos TCP sobre IP. Transportes sem conexão meu ser estabelecida em cima de uns orientados a conexão HTTP sobre TCP.

Pode haver variações sobre estes. Por exemplo, uma sessão pode forçar mensagens que chegam, mas não poderia garantir que eles chegam na ordem enviada. No entanto, estes dois são os mais comuns.

Modelos de Comunicação

Algumas línguas não processuais são construídos sobre o princípio da mensagem que passava. Línguas simultâneas costumam usar esse mecanismo, e o exemplo mais bem conhecido é provavelmente o oleoduto Unix. O gasoduto Unix é um pipeline de bytes, mas não há uma inerente limitação: a Microsoft PowerShell pode enviar objetos ao longo de seus oleodutos e línguas em simultâneo, como Parlog poderia enviar estruturas de dados lógica arbitrários em mensagens entre processos concorrentes.

Passagem de mensagens é um mecanismo primitivo para sistemas distribuídos. Configurar uma conexão e bombear alguns dados para baixo dele. Na outra fim, descobrir qual era a mensagem e responder a ela, possivelmente, o envio de mensagens de volta. Isto é ilustrado pela Evento Baixo nível de sistemas acionados, tais como a função X Window System de uma forma um pouco semelhante: esperar pela mensagem de um usuário (cliques de mouse, etc), decodificá-las e agir sobre eles.

Sistemas dirigidos por eventos de nível superior supor que esta decodificação foi feito pelo sistema subjacente e, em seguida, o evento é despachados para um objeto apropriado, como um manipulador ButtonPress. Isto também pode ser feito de passagem de mensagens distribuídas sistemas, em que uma mensagem recebida através da rede é parcialmente decodificados e enviados para um manipulador apropriado.

Chamada de procedimento remoto

Em qualquer sistema, há uma transferência de informação e de controlo de fluxo a partir de uma parte do sistema para outra. Em linguagens procedurais esta pode consistir na chamada de procedimento, onde a informação é colocada em uma pilha de chamadas e, em seguida, o fluxo de controle é transferido para outra parte do programa.

Mesmo com chamadas de procedimento, há variações. O código pode ser estaticamente ligado de modo que a transferência de controle de uma parte do código executável do programa para outra parte. Devido ao aumento do uso de rotinas de biblioteca, tornou-se comum ter tais código em bibliotecas de vínculo dinâmico (DLL), onde as transferências de controle para uma peça independente de código.

A mecânica não são tão simples! No entanto, este modelo de controle tem dado origem ao "procedimento remoto é um passo simples (conceitual) para transferir o controle para um procedimento que funciona em um chamar "(RPC) que é discutido em muitos detalhes em um capítulo posterior.

VISITE UMA IGREJA EVANGELICA

Page 42: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Há uma estranheza histórica chamada de "leve chamada de procedimento remoto" inventado pela Microsoft como a transição de 16 bits para Aplicativos de 32 bits. A aplicação de 16 bits pode precisar transferir dados para um aplicativo de 32 bits na mesma máquina. Isso fez com que ele leve, pois não havia rede! Mas tinha muitas das outras questões de sistemas de RPC em representações de dados e conversão.

Modelos de computação distribuída

Na maior nível, podemos considerar a equivalência ou a não equivalência dos componentes de um sistema de distribuição. A maioria ocorrência comum é uma assimétrica um: um cliente envia pedidos para um servidor, e servidor responde. Este é um cliente servidor sistema.

Se ambos os componentes são equivalentes, ambos capazes de iniciar e responder a mensagens, em seguida, temos um sistema peer-to-peer. Nota que esta é uma classificação lógica: um peer pode ser um mainframe 16.000 core, o outro pode ser um telefone celular. Mas se ambos podem ato similar lym então eles são pares

Um terceiro modelo é o filtro de chamada. Aqui um componente passa a informação para outra que modificá-lo antes de passá-la para um terceiro. Este é um modelo bastante comum: por exemplo, o componente do meio obtém informações a partir de um banco de dados como SQL e registros transforma o em uma tabela HTML para o terceiro componente (que pode ser um navegador).

Estes são ilustrados como:

Sistema Cliente / Servidor

VISITE UMA IGREJA EVANGELICA

Page 43: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Outro ponto de vista de um sistema cliente servidor é

Aplicação Cliente / Servidor

E um terceiro ponto de vista é

Servidor Distribuído

A sistemas cliente servidor não precisa ser simples. O modelo básico é o cliente único, único servidor.

Mas você também pode ter vários clientes, único servidor

Neste, o mestre recebe os pedidos e, em vez de tratá-los um a si mesmo um tempo, passá-las para outros servidores para manipular.

Este é um modelo comum quando são possíveis clientes simultâneos.

VISITE UMA IGREJA EVANGELICA

Page 44: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Há também único cliente, vários servidores que ocorre frequentemente quando um servidor precisa agir como um cliente para outro servidores, como um servidor de lógica de negócios a obtenção de informações a partir de um servidor de banco de dados. Com vários servidores. E, claro, não poderia haver vários clientes

Componente de Distribuição

Uma maneira simples, mas eficaz, de decompor muitas aplicações é considerá-los como composta de três partes:

Componente Apresentação A lógica da aplicação Acesso a dados

O componente de apresentação é responsável pela interação com o usuário, tanto a apresentação de dados e coleta de entrada. Pode ser um interface gráfica moderna, com botões, listas, menus, etc, ou uma interface mais velho estilo de linha de comando, fazendo perguntas e obtendo respostas. Os detalhes não são importantes a este nível.

A lógica do aplicativo é responsável por interprete as respostas dos usuários, para a aplicação de regras de negócio, para consultas de preparação e gestão respostas do componente thir.

O componente de acesso a dados é responsável pelos dados stroing e recuperar. Este será muitas vezes por meio de uma base de dados, mas não necessariamente.

Gartner Classificação

Com base nesta decomposição tríplice de applicaitons, o Gartner considera a forma como os componentes podem ser distribuídos em um cliente system servidor. Eles vieram com cinco modelos:

Exemplo: Banco de Dados Distribuídos

Classificação Gartner: 1

Os telefones móveis modernos são bons exemplos disso: devido à memória limitada podem armazenar uma pequena parte de um banco de dados localmente para que podem responder rapidamente.

VISITE UMA IGREJA EVANGELICA

Page 45: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Banco de dados para que os dados adicionais.No entanto, se os dados é necessária, que não é realizada no local, em seguida, uma solicitação

pode ser feita para um remoto Google Maps faz outro bom exemplo. Al dos mapas residem nos servidores do Google. Quando a pessoa é solicitada por um usuário, o mapas "próximas" são baixado também em um pequeno banco de dados no navegador. Quando o usuário move o mapa um pouco, os bits extras necessário já está na loja local para resposta rápida.

Exemplo: Rede de Atendimento do Arquivo

Classificação Gartner 2 permite que clientes remotos acesso a um sistema de arquivos compartilhado

Há muitos exemplos de sistemas scuh: NFS, as ações da Microsoft, DCE, etc

Exemplo: Web

Um exemplo de classificação Gartner 3 é a Web com applets Java. Este é um sistema de hipertexto distribuído, com muitos adicional mecanismos

Exemplo: emulação de terminal

Um exemplo de classificação Gartner 4 é emulação de terminal. Isto permite que um sistema de telecomando para atuar como um terminal normal numa locais sistema.

Telnet é o exemplo mais comum deste.

Exemplo: Expert

Esperar é uma ilustração do romance de classificação Gartner 5. Ele atua como um wrapper em torno

VISITE UMA IGREJA EVANGELICA

Page 46: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

de um sistema clássico, como uma linha de comando interface. Ele cria uma interface X Window em torno deste, de modo que o usuário interage com uma interface gráfica, e GUI, por sua vez interage com o interface de linha de comando.

Exemplo: X Window System

O próprio Sistema X Window é um exemplo de classificação Gartner 5. Uma aplicação faz chamadas GUI, tais como, Mas estes DrawLine não são tratados diretamente, mas em vez passou a um servidor X Window para renderização. Isso separa a visualização do aplicativo de janelas e a vista de exibição de janelas.

Três modelos de camada

É claro, se você tem duas camadas, então você pode ter três, quatro, ou mais. Alguns dos três possibilidades camadas são mostrados neste Diagrama:

O moderno Web é um bom exemplo da direita destes. O método é composto por um banco de dados, muitas vezes funcionando armazenados procedimentos para realizar parte da lógica de banco de dados. A camada intermediária é um servidor HTTP como o Apache executando scripts PHP (ou Ruby ou Páginas Rails, ou JSP, etc.) Isso vai gerir parte da lógica e terá dados como páginas HTML armazenados localmente. O frontend é um navegador para exibir as páginas, sob o controlo de alguns Javascript. No HTML 5, a interface também pode ter um banco de dados local.

VISITE UMA IGREJA EVANGELICA

Page 47: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Largo vs estreito

A rotulagem de componentes em comum é "largo" ou "estreito". Componentes de gordura ocupam muita memória e fazer o processamento complexo. Estreito componentes, por outro lado, fazer pouco de ambos. Não parece haver qualquer componentes de tamanho "normal", só largo ou estreito!

Gordura ou magreza é um conceito relativo. Browsers são frequentemente laelled tão estreito, porque "tudo que eles fazem é páginas web diplay". Firefox em minha caixa de Linux leva quase 1/2 de um gigabyte de memória, que eu não considero tão pequeno em tudo!

Modelo Middleware

Middleware é teh "cola" que liga os componentes de um sistema distribuído. O modelo de middleware é

Middleware

Componentes de middleware incluem Os serviços de rede incluem coisas como TCP / IP A camada de middleware é s independente do aplicativo / w usando os serviços de rede Exemplos de middleware são: DCE, RPC, Corba Middleware pode desempenhar apenas uma função (como a RPC) ou muitos (como DCE)

Exemplos Middleware

Exemplos de middleware incluem Serviços primitivos, como emuladores de terminais, transferência de arquivos, e-mail Serviços básicos como RPC Serviços integrados, como DCE, Rede O / S Serviços de objetos distribuídos, como CORBA, OLE / ActiveX Objeto serviços móveis, como RMI, Jini World Wide Web

Funções de middleware

As funções de middleware incluem Iniciação de processos em diferentes computadores Gerenciamento de sessão Os serviços de diretório para permitir que os clientes a localizar servidores acesso remoto aos

VISITE UMA IGREJA EVANGELICA

Page 48: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

dados Controle de concorrência para permitir que servidores para lidar com vários clientes Segurança e integridade Monitoração Rescisão de processos local e remoto

Continuo de Processamento

O modelo Gartner é baseado em uma quebra de uma aplicação em componentes de apresentação, lógica de aplicação e dados manuseamento. A mais estreito quebra de grão é

Pontos de falha

Aplicações distribuídas executado em um ambiente complexo. Isso os torna muito mais propensos a falhas de aplicativos independentes sobre um único computador. Os pontos de falha incluem

O lado cliente do aplicativo pode falhar O sistema cliente pode ter h / w problemas Placa de rede do cliente pode falhar Contenção de rede poderia causar timeouts Pode haver conflitos de endereços de rede Os elementos da rede, como roteadores poderia deixar Erros de transmissão pode perder mensagens As versões cliente e servidor pode ser incompatível Placa de rede do servidor pode falhar O sistema de servidor pode ter h / w problemas O servidor s / w pode falhar

Banco de dados do servidor pode ser corrompidoOs pedidos têm de ser concebidos com estas possíveis falhas em mente. Qualquer ação realizada

por um componente deve ser recuperável se a falha ocorre em alguma outra parte do sistema. Técnicas como transações e erro contínua necessidade verificando a ser utilizada para evitar os erros.

Fatores de Aceitação

Atuação Receptividade

VISITE UMA IGREJA EVANGELICA

Page 49: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Escalabilidade Capacidade Segurança

Transparência

Os "cálices sagrados" de sistemas distribuídos devem fornecer o seguinte:

Transparência acesso Transparência de localização Transparência migração Transparência replicação Transparência de concorrência Transparência escalabilidade Transparência desempenho Transparência falha

Oito falácias da computação distribuída

Sun Microsystems foi uma empresa que realizou a maior parte do trabalho inicial em sistemas distribuídos, e ainda teve um mantra "O rede é o computador. "Com base em sua experiência ao longo de muitos anos um número de cientistas da Sun veio com a seguinte lista de falácias comumente assumidas:

1. A rede é de confiança.2. A latência é zero.3. Largura de banda é infinita.4. A rede é segura.5. Topologia não muda.6. Existe um administrador.7. Custo de transporte é zero.8. A rede é homogênea.

Muitas delas impactam diretamente sobre a programação da rede. Com a premissa de que a rede é de confiança de modo a que uma chamada de procedimento remota Irá comportar-se da mesma forma como uma chamada local. Por exemplo, a concepção da maior parte dos sistemas de chamadas de procedimento remotas baseia zero banda latência e infinita também levar a suposições sobre o tempo de duração de uma chamada RPC sendo o mesmo como um local de As falácias ligar, ao passo que são grandezas de ordem mais lentas.

O reconhecimento dessas falácias levou o modelo de Java RMI (Remote Method Invocation) a exigir que cada chamada RPC para potencialmente lançar um. Isto forçou os programadores a, pelo menos, reconhecer a possibilidade de erro de rede e para lembrá-los de que eles RemoteException não poderia esperar que as mesmas velocidades como chamadas locais.

PROTOCOLOS

3.2 A pilha TCP / IP

O modelo OSI foi criado através de um processo em que o comitê padrão foi criado e, em seguida, implementados. Algumas partes do o padrão OSI são obscuras, algumas peças não podem ser facilmente implementadas, algumas partes não foram implementadas.

O protocolo TCP / IP foi criado através de um projeto DARPA de longa duração. Isso funcionou por implementação seguido por RFCs (Request For Comment). TCP / IP é o principal protocolo de rede Unix. TCP / IP = Transmission Control Protocol / Internet

Protocolo.

VISITE UMA IGREJA EVANGELICA

Page 50: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

A pilha TCP / IP é mais curto do que o OSI one:

O TCP é um protocolo orientado a conexão, o UDP (User Datagram Protocol) é um protocolo sem conexão.

Datagramas IP

A camada IP oferece um sistema de entrega sem conexão e não confiável. Ele considera cada datagrama independentemente dos outros.

Qualquer associação entre datagramas devem ser fornecidos pelas camadas mais altas.A camada IP fornece uma soma de verificação que inclui o seu próprio cabeçalho. O cabeçalho inclui

os endereços de origem e de destino.A camada IP lida com encaminhamento através de uma Internet. Ele também é responsável pela

quebra de grandes datagramas em partes menores para transmissão e reunidas na outra extremidade.

UDP

UDP também é sem conexão e não confiável. O que ele adiciona ao IP é uma soma de verificação para o conteúdo dos números de datagramas e portuárias.

Estes são utilizados para dar a / modelo cliente servidor ver mais tarde.

TCP

TCP fornece a lógica para dar um protocolo orientado a conexão confiável acima de IP. Ele fornece um circuito virtual que dois processos podem utilizar para se comunicar. Ele também usa números de porta para identificar os serviços em um host.

Adresses Internet

Para utilizar um serviço você deve ser capaz de encontrá-lo. A Internet usa um esquema de endereços para dispositivos como computadores, de modo que eles podem ser localizados. Este esquema de endereçamento foi originalmente concebido, quando havia apenas um punhado de computadores conectados e muito generosamente permitiu até 2 ^ 32 endereços, usando um inteiro não assinado de 32 bits. Estes são os chamados endereços IPv4. Em recente anos, o número de dispositivos conectados (ou pelo menos diretamente endereçáveis) ameaçou ultrapassar esse número, e assim "qualquer dia agora "vamos mudar para o IPv6, que vai permitir que até 2 ^ 128 endereços, usando um inteiro de 128 bits sem sinal. A passagem é mais provável de ser forçado por países emergentes, como o mundo desenvolvido já tomou quase todo o pool de endereços IPv4.

Endereços IPv4

O endereço é um número inteiro de 32 bits que dá o endereço IP. Isso resolve a uma placa de interface de rede em um único dispositivo. O endereço é normalmente composto por quatro bytes em decimal com um ponto '.' entre eles, como em "127.0.0.1" ou "66.102.11.104".

VISITE UMA IGREJA EVANGELICA

Page 51: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

O endereço de IP de qualquer dispositivo é geralmente composta de duas partes: o endereço da rede em que o dispositivo reside, e o endereço do dispositivo nessa rede. Era uma vez, a divisão entre o endereço de rede e endereço interno era simples e foi com base nos bytes usados no endereço IP.

Numa rede de classe A, o primeiro byte identifica na rede, enquanto que os três últimos identificar o dispositivo. Existem apenas 128 classe A redes, pertencentes aos primeiros jogadores no espaço de internet, como a IBM, a empresa General Electric.

As redes de classe B usam os dois primeiros bytes para identificar a rede e os dois últimos para identificar dispositivos dentro da sub-rede. Este permite que até 2 ^ 16 (65536) dispositivos em uma sub--rede.

As redes de classe C usam os primeiros três bytes para identificar a rede e último para identificar dispositivos dentro dessa rede. Isto permite que até 2 ^ 8 (na verdade, 254, 256) não dispositivos.

Este esquema não funciona bem se você quiser, por exemplo, 400 computadores em uma rede. 254 é muito pequena, enquanto que 65.536 é muito grande. Termos aritméticos, que quiser sobre 512. Isto pode ser conseguido através de um endereço de rede de 23 bits e de 9 bits para os endereços dos dispositivos.

Em binário Da mesma forma, se você quiser até 1.024 dispositivos, você pode usar um endereço de rede 22 bits e um endereço de dispositivo de 10 bits.

Dado um endereço IP de um dispositivo, e saber quantos bits N são utilizados para o endereço de rede proporciona uma relativamente simples processo para extrair o endereço de rede e endereço do dispositivo dentro da rede. Formar uma "máscara de rede", que é um 32bit número binário com todos os que estão nas primeiras posições N e todos os zeros nas restantes. Por exemplo, se 16 bits são utilizados para o endereço de rede, a máscara é 11111111111111110000000000000000. É um pouco inconveniente usando binário, assim bytes decimais são geralmente utilizado. A máscara de rede para endereços de rede de 16 bits é 255.255.0.0, para endereços de rede de 24 bits é 255.255.255.0, enquanto que para 23 bit aborda seria 255.255.254.0 e por 22 endereços bit seria 255.255.252.0.

Depois de encontrar a rede de um dispositivo, bit a bit E é o endereço IP com a máscara de rede, enquanto o endereço do dispositivo dentro do sub rede é encontrado com bit a bit E do 1 complemento da máscara com o endereço de IP.

Os endereços IPv6

A internet tem crescido muito além das expectativas originais. O esquema de endereçamento de 32 bits inicialmente generoso está à beira de esgotando. Existem soluções alternativas desagradáveis, como NAT endereçamento, mas eventualmente vamos ter que mudar para um endereço mais amplo espaço. IPv6 utiliza endereços de 128 bits. Mesmo bytes tornasse complicado para expressar esses endereços, por isso são dígitos hexadecimais utilizados, agrupados em 4 dígitos e separados por dois pontos ':'. Um endereço típico pode ser 2002: c0e8: 82e7: 00:00:00: c0e8: 82e7.

Esses endereços não são fáceis de lembrar! DNS se tornará ainda mais importante. Há truques para reduzir a alguns endereços, como eliding zeros e algarismos repetidos. Por exemplo, "host local" é 0:0:0:0:0:0:0:1, o qual pode ser reduzido para 1:

Tipo de endereço IP 3.4

O tipo de IP

O pacote "net" define vários tipos, funções e métodos de uso em Go programação de rede. O tipo array de bytes

type IP [ ] byte

Existem várias funções para manipular uma variável do tipo IP, Mas é provável que você use apenas alguns deles na prática. Para exemplo, a função ParseIP (String) vai demorar um endereço IPv4 pontilhada ou um endereço IPv6 dois pontos, enquanto o IP método String vontade retornar uma string. Note que você não pode obter de volta o que você começou com: a forma de sequência de 0:0:0:0:0:0:0:1 é :: 1.

Um programa para ilustrar este é

/* IP */

VISITE UMA IGREJA EVANGELICA

Page 52: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

package main

import ( "net" "os" "fmt")

func main( ) { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: %s ip-addr\n", os.Args[0]) os.Exit(1) } name := os.Args[1]

addr := net.ParseIP(name) if addr == nil { fmt.Println("Invalid address") } else { fmt.Println("The address is ", addr.String( )) } os.Exit(0)}

Se este é compilado para o executável IP em seguida, ele pode ser executado, por exemplo, como

IP 127.0.0.1com respostaO endereço é 127.0.0.1ou comoIP 0:0:0:0:0:0:0:1com respostaO endereço é :: 1O tipo ipmaskA fim de lidar com operações de máscara, não é o tipo digitetype IPMask [ ] byteExiste uma função para criar uma máscara de um endereço IPv4 de 4 bytesfunc IPv4Mask (a, b, c, d byte) IPMaskEm alternativa, existe um método de IP que retorna a máscara padrãofunc (ip IP) DefaultMask ( ) IPMask

Note se que a forma de sequência de uma máscara é um número hexadecimal, como FFFF0000 por uma máscara de 255.255.0.0.

A máscara pode ser utilizado por um método de um endereço de IP para encontrar a rede para que o endereço de IP

func (ip IP) Mask ( Mask IPMask) IP

Um exemplo da utilização do presente é o seguinte programa:

/* Mask */import ( "fmt" "net" "os")

func main( ) {

VISITE UMA IGREJA EVANGELICA

Page 53: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: %s dotted-ip-addr\n", os.Args[0]) os.Exit(1) } dotAddr := os.Args[1]

addr := net.ParseIP(dotAddr) if addr == nil { fmt.Println("Invalid address") os.Exit(1) } mask := addr.DefaultMask( ) network := addr.Mask(mask) ones, bits := mask.Size( ) fmt.Println("Address is ", addr.String( ), " Default mask length is ", bits, "Leading ones count is ", ones, "Mask is (hex) ", mask.String( ), " Network is ", network.String( )) os.Exit(0)}

Se este é compilado para Mask e executado por

Mask127.0.0.1

ela retorneO endereço é 127.0.0.1 Comprimento da máscara padrão é 8 Rede é

127.0.0.0

O tipo IPAddr

Muitas das outras funções e métodos do pacote net retornar um ponteiro para um IPAddr. Isto é simplesmente uma estrutura contendo um IP.

type IPAddr {IP IP}

A principal utilização deste tipo é a realização de pesquisas de DNS em nomes de host IP.

func ResolveIPAddr(net, addr string) (*IPAddr, os.Error)

Onde rede é um dos "ip", "IP4" ou "IP6". Isto é mostrado no programa

/* ResolveIP */

package main

import ( "net" "os" "fmt")

func main( ) { if len(os.Args) != 2 {

VISITE UMA IGREJA EVANGELICA

Page 54: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

fmt.Fprintf(os.Stderr, "Usage: %s hostname\n", os.Args[0]) fmt.Println("Usage: ", os.Args[0], "hostname") os.Exit(1) } name := os.Args[1]

addr, err := net.ResolveIPAddr("ip", name) if err != nil { fmt.Println("Resolution error", err.Error( )) os.Exit(1) } fmt.Println("Resolved address is ", addr.String( )) os.Exit(0)}

Correndo Resolveip www.google.com returns

Resolved address is 66.102.11.104

Hospedar pesquisa

A função ResolveIPAddr Irá realizar uma pesquisa de DNS em um nome de host, e retornar um único endereço IP. No entanto, os anfitriões podem ter múltiplos endereços IP, geralmente a partir de vários cartões de interface de rede. Eles também podem ter vários nomes de host, atuando como aliases.

func LookupHost(name string) (cname string, addrs [ ]string, err os.Error)

Um desses endereços serão marcados como o "canônico" nome do host. Se você deseja encontrar o nome canônico, use func

LookupCNAME(name string) (cname string, err os.Error)

/* LookupHost*/

/* LookupHost */

package main

import ( "net" "os" "fmt"

Note que esta função retorna strings, não valores IPEndereço.

Serviços

Serviços executados em máquinas host. Eles normalmente são de longa vida e são projetados para esperar por pedidos e responder a eles. Tem muitos tipos de serviços, e há muitas maneiras em que eles podem oferecer os seus serviços aos clientes. As bases mundiais de internet, muitos dos estes serviços em dois meios de comunicação, o TCP e UDP, embora existam outros protocolos de comunicação, tais como SCTP à espera nos bastidores para assumir. Muitos outros tipos de serviço, tais como peer-to-peer, chamadas de procedimento remoto, agentes de comunicação, e muitos outros são construídos em cima de TCP e UDP.

Portas

VISITE UMA IGREJA EVANGELICA

Page 55: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Serviços de viver em máquinas host. O endereço IP Irá localizar o host. Mas em cada computador pode ser muitos serviços, e um simples maneira é necessária para distinguir entre os dois. O método utilizado pela TCP, UDP, SCTP e outros, é a utilização de um número de porta. Este é um inteiro sem sinal beween 1 e 65.535 e cada serviço vai associar-se com um ou mais desses números de porta.

Há muitas portas "padrão". Telnet geralmente usa a porta 23 do protocolo TCP. DNS usa a porta 53, seja com TCP ou com UDP. FTP usa as portas 21 e 20, um para os comandos, o outro para transferência de dados. HTTP geralmente usa a porta 80, mas muitas vezes usa portas 8000, 8080 e 8088, todos com TCP. O Sistema X Window, muitas vezes leva as portas 60006007, tanto em TCP e UDP.

Em um sistema Unix, as portas comumente usados estão listados no arquivo / etc / services. Go tem uma função de interrogar este arquivo

func LookupPort(network, service string) (port int, err os.Error)

O argumento de rede é uma string como "TCP" ou "UDP", enquanto que o serviço é uma string como "telnet" ou "domínio" (por DNS).

Um programa usando este é

/* LookupPort*/

package main

import ( "net" "os" "fmt")

func main( ) { if len(os.Args) != 3 { fmt.Fprintf(os.Stderr, "Usage: %s network-type service\n", os.Args[0]) os.Exit(1) } networkType := os.Args[1] service := os.Args[2]

port, err := net.LookupPort(networkType, service) if err != nil { fmt.Println("Error: ", err.Error( )) os.Exit(2) }

fmt.Println("Service port ", port) os.Exit(0)}

Por exemplo, executando LookupPort tcp telnet impresso Service port: 23

O tipo TCPAddr

O tipo TCPAddr representa uma estrutura contendo um IP um port:

type TCPAddr struct {IPIPPort int

VISITE UMA IGREJA EVANGELICA

Page 56: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

}

A função para criar uma TCPAddr é ResolveTCPAddr

func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)

Onde net é um dos "TCP", "tcp4" ou "tcp6" e o addr é uma string composta de um nome de host ou o endereço IP, seguido pelo porto número após um ":"., como "www.google.com:80" ou '127.0.0.1:22 "se o endereço é um endereço IPv6, que já tem dois pontos em, então a parte de host deve ser colocado entre colchetes, como "[:: 1]: 23". Outro caso especial é usado frequentemente para servidores, onde o endereço do host é zero, de modo que o endereço TCP é realmente apenas o nome da porta, como em ": 80" para um servidor HTTP.

TCP Sockets

Quando você sabe como chegar a um serviço através da sua rede e porta IDs, o que então? Se você é um cliente, você precisa de uma API que permitirá que você se conectar a um serviço e, em seguida, para enviar mensagens para esse serviço e ler as respostas de volta do serviço.

Se você é um servidor, você precisa ser capaz de se ligar a uma porta e ouvir isso. Quando uma mensagem chega você precisa ser capaz de lê-lo e escrever de volta para o cliente.

O net.TCPConn é o tipo Go que permite a comunicação full duplex entre o cliente e servidor. Dois métodos principais de interesse são

func (c *TCPConn) Write(b [ ]byte) (n int, err os.Error)func (c *TCPConn) Read(b [ ]byte) (n int, err os.Error)

Uma Tcpconn é utilizado por um cliente e um servidor para ler e escrever mensagens.

Cliente TCP

Uma vez que um cliente estabeleceu um endereço TCP para um serviço, ele "disca" o serviço. Se bem sucedido, o mostrador retorna um para Tcpconn comunicação. O cliente e servidor trocam mensagens sobre este assunto. Normalmente, um cliente escreve um pedido para o servidor usando a função

func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)

Onde laddr é o endereço local, que geralmente é definido como e RADDR é o endereço remoto do serviço, e a string é um zero rede de "tcp4", "tcp6" ou "tcp", dependendo se você quer uma conexão TCPv4, uma conexão TCPv6 ou não se importam.

Um exemplo simples pode ser fornecido por um cliente para um servidor web (HTTP). Nós vamos lidar substancialmente mais detalhe com clientes HTTP e servidores em um capítulo posterior, mas por agora nós vamos mantê-lo simples.

Uma das possíveis mensagens que um cliente pode enviar a mensagem é "Cabeça". Esta consulta um servidor para obter informações sobre o servidor e um documento no servidor. O servidor retorna as informações, mas não retorna o próprio documento. O pedido enviado para consultar um servidor HTTP pode ser

"HEAD / HTTP/1.0\r\n\r\n"

Que pede informações sobre o documento raiz e servidor. Uma resposta típica poderia ser

HTTP/1.0 200 OKETag: "-9985996"Last-Modified: Thu, 25 Mar 2010 17:51:10 GMTContent-Length: 18074Connection: closeDate: Sat, 28 Aug 2010 00:43:48 GMTServer: lighttpd/1.4.23

VISITE UMA IGREJA EVANGELICA

Page 57: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Primeiro, dar ao programa (GetHeadInfo.go) para estabelecer a conexão para um endereço TCP, enviar a string pedido, ler e imprimir a resposta. Uma vez compilado que pode ser invocado por exemplo

GetHeadnfo www.google.com:80

O programa é

/* GetHeadInfo*/

*/package main

import ( "net" "os" "fmt" "io/ioutil")

func main( ) { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: %s host:port ", os.Args[0]) os.Exit(1) } service := os.Args[1]

tcpAddr, err := net.ResolveTCPAddr("tcp4", service) checkError(err)

conn, err := net.DialTCP("tcp", nil, tcpAddr) checkError(err)

_, err = conn.Write([ ]byte("HEAD / HTTP/1.0\r\n\r\n")) checkError(err)

/ /result, err := readFully(conn) result, err := ioutil.ReadAll(conn) checkError(err) fmt.Println(string(result))

os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

O primeiro ponto a ser observado é a quantidade quase excessivo de verificação de erro que está acontecendo. Isso é normal para programas de rede:

As oportunidades para o fracasso são substancialmente maiores do que para programas independentes. Hardware pode falhar no cliente, o servidor, ou em qualquer um dos roteadores e switches no meio, a comunicação pode ser bloqueada por um firewall, o tempo limite pode ocorrer devido a rede carregar, o servidor pode falhar enquanto o cliente está falando com ele. As seguintes verificações são realizadas:

VISITE UMA IGREJA EVANGELICA

Page 58: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

1. Pode haver erros de sintaxe no endereço especificado2. A tentativa de se conectar ao serviço remoto pode falhar. Por exemplo, o serviço solicitado não

pôde ser executado, ou não pode haver tal hospedeiro ligado à rede3. Embora a conexão foi estabelecida, escreve para o serviço pode falhar se a conexão morreu de

repente, ou o vezes fora da rede4. Do mesmo modo, as leituras podem falhar

Leitura a partir do servidor requer um comentário. Neste caso, podemos ler essencialmente uma única resposta a partir do servidor. Este será denunciado por fim de arquivo na conexão. No entanto, ele pode consistir em vários pacotes TCP, por isso precisamos manter a leitura até o fim do arquivo. O vai cuidar dessas questões e retornar a resposta completa. Há algumas questões de linguagem envolvidas. Primeiro, a maioria das funções de devolver um valor dupla, com possibilidade de erro como segundo valor.

Em C, o mesmo comportamento é obtido por valores especiais, tais como ou 1, ou zero estão sendo devolvidos zero NULL se nenhum se isso é possível. Em Java, a mesma verificação de erros é gerido por jogar e pegar exceções, o que pode tornar a aparência de código muito confuso.

Em versões anteriores do programa, voltei o resultado na array buf, Que é do tipo [512] byte. As tentativas de coagir a um string falharam apenas arrays de bytes do tipo

[ ] Byte pode ser coagido. Isto é um pouco de um incômodo.Um servidor de Daytime Sobre o serviço mais simples que podemos construir é o serviço diurno. Este

é um serviço de Internet, definido pela RFC 867, com um porta padrão de 13, em ambos TCP e UDP. Infelizmente, com o aumento (justificado) em paranoia com a segurança, dificilmente sites executar um servidor dia mais. Nunca mente, podemos construir o nosso próprio. (Para os interessados, se você instalar inetd em seu sistema, você geralmente se um servidor dia jogado dentro)

Um servidor se registra em uma porta e escuta nessa porta. Em seguida, ele blocos em uma operação "aceitar", à espera de clientes para se conectar.

Quando um cliente se conecta, a aceitar chamada retorna, com um objeto de conexão. O serviço durante o dia é muito simples e só escreve o tempo atual para o cliente, fecha a conexão, e retoma à espera do próximo cliente.

As chamadas são relevantes

func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)func (l *TCPListener) Accept( ) (c Conn, err os.Error)

O argumento net pode ser definido como uma das strings "tcp", "tcp4" ou "tcp6". O endereço IP deve ser ajustado para zero, se você quiser escutar em todas as interfaces de rede, ou para o endereço IP de uma única interface de rede, se você só quer ouvir nessa interface. Se o porta é definido como zero, então o O / S Irá escolher uma porta para você. Caso contrário, você pode escolher o seu próprio. Note-se que em um sistema Unix, você não se pode escutar em uma porta abaixo de 1024, a menos que você é o supervisor do sistema, de raiz, e as portas inferiores a 128 são padronizados pelo IETF.

O programa de exemplo escolhe porta 1200 para nenhuma razão particular. O endereço TCP é dado como ": 1200" todas as interfaces, a porta 1200.

O programa é

/* DaytimeServer */package main

import ( "fmt" "net" "os" "time")

func main( ) {

service := ":1200" tcpAddr, err := net.ResolveTCPAddr("ip4", service)

VISITE UMA IGREJA EVANGELICA

Page 59: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { conn, err := listener.Accept( ) if err != nil { continue

} }

daytime := time.Now( ).String( ) conn.Write([ ]byte(daytime)) / / don't care about return value conn.Close( ) / / we're finished with this client }}

func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

Se você executar este servidor, ele só vai esperar lá, não fazer muito. Quando um cliente se conecta a ele, ele vai responder enviando o dia string para ele e, em seguida, retornar à espera para o próximo cliente.

Note-se a manipulação de erros alterado no servidor, em comparação com um cliente. O servidor deve executar para sempre, de modo que se ocorrer algum erro com um cliente, o servidor simplesmente ignora esse cliente e continua. Um cliente de outra forma poderia tentar atrapalhar a conexão com o servidor, e trazê-lo para baixo!

Nós não construímos um cliente. Isso é fácil, basta mudar o cliente anterior para omitir a gravação inicial. Em alternativa, basta abrir um telnet conexão com esse host:

telnet localhost 1200

I$telnet localhost 1200Trying ::1...Connected to localhost.Escape character is '^]'.Sun Aug 29 17:25:19 EST 2010Connection closed by foreign host.

Onde "Sun 29 de agosto 17:25:19 EST 2010" é a saída do servidor.

Servidor multithreaded

"Echo" é outro serviço simples IETF. Isso só lê o que os tipos de cliente e enviá-lo de volta:

/* SimpleEchoServer */package main

import ( "net" "os" "fmt")

VISITE UMA IGREJA EVANGELICA

Page 60: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

func main( ) {

service := ":1201" tcpAddr, err := net.ResolveTCPAddr("tcp4", service) checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { conn, err := listener.Accept( ) if err != nil { continue } handleClient(conn) conn.Close( ) / / we're finished }}

func handleClient(conn net.Conn) { var buf [512]byte for { n, err := conn.Read(buf[0:]) if err != nil { return } fmt.Println(string(buf[0:])) _, err2 := conn.Write(buf[0:n]) if err2 != nil { return } }}func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

Enquanto isso funciona, há uma questão importante com este servidor: é singlethreaded. Enquanto um cliente tem uma conexão aberta com ele, nenhum outro cllient pode se conectar. Outros clientes são bloqueados, e, provavelmente, Irá expeirar. Felizmente esta é easly fixo, fazendo o processador cliente uma rotina de Go. Também passaram a estreita ligação para o manipulador, pois agora pertence lá

/* ThreadedEchoServer*/

/* ThreadedEchoServer */package main

import ( "net" "os" "fmt")

func main( ) {

VISITE UMA IGREJA EVANGELICA

Page 61: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

service := ":1201" tcpAddr, err := net.ResolveTCPAddr("ip4", service) checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err) for { conn, err := listener.Accept( ) if err != nil { continue } / / run as a goroutine go handleClient(conn) }}

func handleClient(conn net.Conn) { / / close connection on exit defer conn.Close( )

var buf [512]byte for { / / read upto 512 bytes n, err := conn.Read(buf[0:]) if err != nil { return }

/ / write the n bytes read _, err2 := conn.Write(buf[0:n])

return } }}func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

Controlar conexões TCP

Timeout

O servidor pode querer tempo limite um cliente se ele não responder com suficiente rapidez que o IE não escrever um pedido para o servidor no tempo.

Este deve ser um longo período (alguns minutos), pois o usuário pode tomar seu tempo. Por outro lado, o cliente pode querer o tempo limite do servidor (depois de um tempo muito mais curto). Ambos fazem isso

func (c *TCPConn) SetTimeout(nsec int64) os.Error

Antes de qualquer lê ou escreve no soquete.

Permanecer vivo

VISITE UMA IGREJA EVANGELICA

Page 62: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Um cliente pode querer ficar ligado a um servidor, mesmo que ele não tem nada para enviar. Pode usar

func (c * tcpconn) SetKeepAlive (keepalive bool) os.ErrorExistem vários outros métodos de controle de conexão, documentados no pacote "net".

UDP datagramas

Em um protocolo sem conexão cada mensagem contém informações sobre a sua origem e destino. Não há "sessão" estabelecida usando um soquete de vida longa. Clientes e servidores UDP fazer uso de datagramas, que são as mensagens individuais contendo fonte e informações sobre o destino. Não há um estado mantido por essas mensagens, a menos que o cliente ou o servidor faz isso. As mensagens são não é garantido para chegar, ou podem chegar fora de ordem.

A situação mais comum para um cliente é enviar uma mensagem e espero que a resposta chegue. A situação mais comum para uma servidor seria receber uma mensagem e, em seguida, enviar uma ou mais respostas de volta para esse cliente. Em uma situação de peer-to-peer, porém,

O servidor pode apenas encaminhar mensagens para outros colegas.A principal diferença entre TCP e UDP para manuseio Go é como lidar com os pacotes que chegam a

partir, possivelmente, vários clientes, sem a almofada de uma sessão TCP para gerenciar as coisas. As principais chamadas são necessários

func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error)func DialUDP (string net, laddr, RADDR * UDPAddr) (c * UDPConn, err os.Error)func ListenUDP (string net, laddr * UDPAddr) (c * UDPConn, err os.Error)func (c * UDPConn) ReadFromUDP (byte b [ ]) (n int, addr * UDPAddr, err os.Errorfunc (c * UDPConn) WriteToUDP (b [ ] byte, addr * UDPAddr) (n int, err os.Error)

O cliente de um serviço de tempo UDP não precisa fazer muitas mudanças, apenas mudando TCP ... ...chamadas para UDP ... ...chama:

/* UDPDaytimeClient*/

import ( "net" "os" "fmt")

func main( ) { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0]) os.Exit(1) } service := os.Args[1]

udpAddr, err := net.ResolveUDPAddr("up4", service) checkError(err)

conn, err := net.DialUDP("udp", nil, udpAddr) checkError(err)

_, err = conn.Write([ ]byte("anything")) checkError(err)

var buf [512]byte n, err := conn.Read(buf[0:]) checkError(err)

fmt.Println(string(buf[0:n]))

VISITE UMA IGREJA EVANGELICA

Page 63: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

os.Exit(0)}func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error ", err.Error( )) os.Exit(1) }}

Outro

/* UDPDaytimeServer */package main

import ( "fmt" "net" "os" "time")

func main( ) {

service := ":1200" udpAddr, err := net.ResolveUDPAddr("up4", service) checkError(err)

conn, err := net.ListenUDP("udp", udpAddr) checkError(err)

for { handleClient(conn) }}

func handleClient(conn *net.UDPConn) {

var buf [512]byte

_, addr, err := conn.ReadFromUDP(buf[0:]) if err != nil { return }

daytime := time.Now( ).String( )

conn.WriteToUDP([ ]byte(daytime), addr)}

func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error ", err.Error( )) os.Exit(1) }}

Servidor escutando tomadas múltiplas

VISITE UMA IGREJA EVANGELICA

Page 64: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Um servidor pode estar tentando ouvir vários clientes e não apenas em uma porta, mas em muitos. Neste caso, ele tem que usar algum tipo de mecanismo de pesquisa entre os portos.

No C, a ( ) chamada de seleção permite que o kernel fazer este trabalho. A chamada tem um número de descritores de arquivos. O processo é suspenso. Quando I / O é preparado por um destes, um despertador é feito, e o processo pode continuar. Esta é mais barato do que ocupado polling. No Go, realizar a mesmo usando um goroutine diferente para cada porta. Um segmento vai se tornar executável quando o nível mais baixo select ( ) descobre que I / O é pronto para esta discussão.

Os tipos de Conn, PacketConn e Listener

Até agora, temos diferenciado entre a API para TCP e UDP para o API, usando, por exemplo e DialUDP

Retornando uma DialTCP e UDPConn respectivamente. O tipo é um interface e tanto Tcpconn e UDPConn implementa essa interface. Para um grande Tcpconn Conn medida em que você pode lidar com esta interface em vez de os dois tipos.

Em vez de funções de discagem separados para TCP e UDP, você pode usar uma única função Dial func (net, laddr, string RADDR) (c Conn, err os.Error)

O net pode ser qualquer um "tcp", "tcp4" (IPv4only), "tcp6" (IPv6only), "udp", "udp4" (IPv4only), "udp6" (IPv6only), "ip "," IP4 "(Ipv4 apenas) e "IP6" IPv6only). Ele Irá retornar uma implementação apropriada do interface. Note que esta função recebe uma string Conn em vez de endereço como argumento raddr, para que os programas que utilizam este pode evitar trabalhando fora o tipo de endereço em primeiro lugar.

Usando esta função faz pequenas alterações aos programas. Por exemplo, o programa anterior para obter informações CABEÇA de uma página da Web pode ser reescrita como

/* IPGetHeadInfo */package main

import ( "bytes" "fmt" "io" "net" "os")

func main( ) { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0]) os.Exit(1) } service := os.Args[1]

conn, err := net.Dial("tcp", service) checkError(err)

_, err = conn.Write([ ]byte("HEAD / HTTP/1.0\r\n\r\n")) checkError(err)

result, err := readFully(conn) checkError(err)

fmt.Println(string(result)) os.Exit(0)}

func checkError(err error) { if err != nil {

VISITE UMA IGREJA EVANGELICA

Page 65: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

func readFully(conn net.Conn) ([ ]byte, error) { defer conn.Close( )

result := bytes.NewBuffer(nil) var buf [512]byte for { n, err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil, err } } return result.Bytes( ), nil}

Escrever um servidor pode ser simplificado de modo semelhante utilizando a função

func Listen(net, laddr string) (l Listener, err os.Error)

Que retorna um objeto implementar a interface Listene. Este interface tem um método

func (l Listener) Aceitar ( ) (c Conn, err os.Error)

o que permitIrá que um servidor a ser construído. Usando isso, o servidor de eco multi threaded dado torna-se mais cedo

/* ThreadedIPEchoServer */package main

import ( "fmt" "net" "os")

func main( ) {

service := ":1200" listener, err := net.Listen("tcp", service) checkError(err) for { conn, err := listener.Accept( ) if err != nil { continue } go handleClient(conn) }}

VISITE UMA IGREJA EVANGELICA

Page 66: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

func handleClient(conn net.Conn) { defer conn.Close( )

var buf [512]byte for { n, err := conn.Read(buf[0:]) if err != nil { return } _, err2 := conn.Write(buf[0:n]) if err2 != nil { return } }}

func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }

Se você quiser escrever um servidor UDP, então não há uma interface PacketConn e um método para retornar uma implementação deste:

func ListenPacket(net, laddr string) (c PacketConn, err os.Error)

Esta interface possui métodos ReadFrom primários e WriteTo para lidar com pacotes lê e escreve. Sockets

O de rede pacote GO recomenda o uso desses tipos de interface em vez do que os de concreto. Mas ao usá-los, você perde específico. Métodos tais como SetKeepAlive ou Tcpconn e SetReadBuffer deUDPConn , A menos que você faça uma conversão de tipo. É sua escolha.

soquetes primas e do tipo IPConn

Esta seção abrange material avançado que a maioria dos programadores é improvável que precisa. Trata-se de raw sockets, que permitem a programador para construir seus próprios protocolos IP, ou usar diferentes protocolos TCP ou UDP

TCP e UDP não são os únicos protocolos construídos acima da camada IP. O sitehttp:/ /www.iana.org/assignments/protocolnumbers lists, cerca de 140 deles (esta lista é frequentemente disponíveis em sistemas Unix no arquivo). TCP e UDP são apenas os números 6 e 17 / etc / protocolos respectivamente nesta lista.

Go permite que você construa chamados soquetes simples, para que você possa se comunicar usando um desses outros protocolos, ou mesmo para construir seu próprio país. Mas dá suporte mínimo: ele Irá se conectar exércitos, e escrever e ler pacotes entre os hosts. No próximo capítulo, vai olhar para projetar e implementar os seus próprios protocolos TCP acima; esta seção considera o mesmo tipo de problema, mas, ao Camada IP.

Para manter as coisas simples, vamos usar quase o mais simples possível exemplo: como enviar uma mensagem de ping para um host. Ping utiliza o "Echo" comando a partir do protocolo ICMP. Este é um protocolo orientado de byte, em que o cliente envia um fluxo de bytes para outra hospedar, e anfitrião responde. O formato é:

O primeiro byte é 8, de pé para a mensagem de eco O segundo byte é zero O terceiro e quarto bytes são uma soma de verificação em toda a mensagem Os quinto e sexto bytes são um Identificador arbitrária

VISITE UMA IGREJA EVANGELICA

Page 67: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Os sétimo e oito bytes são um número de sequência arbitrária O restante do pacote de dados de utilizador é

O programa a seguir vai preparar uma conexão IP, envie uma solicitação de ping para um host e obter uma resposta. Você pode precisar de ter raiz acesso, a fim de executá-lo com sucesso.

/* Ping */package main

import ( "bytes" "fmt" "io" "net" "os")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host") os.Exit(1) }

addr, err := net.ResolveIPAddr("ip", os.Args[1]) if err != nil { fmt.Println("Resolution error", err.Error( )) os.Exit(1) }

conn, err := net.DialIP("ip4:icmp", addr, addr) checkError(err)

var msg [512]byte msg[0] = 8 / / echo msg[1] = 0 / / code 0 msg[2] = 0 / / checksum, fix later msg[3] = 0 / / checksum, fix later msg[4] = 0 / / identifier[0] msg[5] = 13 / /identifier[1] msg[6] = 0 / / sequence[0] msg[7] = 37 / / sequence[1] len := 8

check := checkSum(msg[0:len]) msg[2] = byte(check >> 8) msg[3] = byte(check & 255)

_, err = conn.Write(msg[0:len]) checkError(err)

_, err = conn.Read(msg[0:]) checkError(err)

fmt.Println("Got response") if msg[5] == 13 { fmt.Println("identifier matches") } if msg[7] == 37 {

VISITE UMA IGREJA EVANGELICA

Page 68: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

fmt.Println("Sequence matches") }

os.Exit(0)}

func checkSum(msg [ ]byte) uint16 { sum := 0

/ / assume even for now for n := 1; n < len(msg)-1; n += 2 { sum += int(msg[n])*256 + int(msg[n+1]) } sum = (sum >> 16) + (sum & 0xffff) sum += (sum >> 16) var answer uint16 = uint16(^sum) return answer}

func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

func readFully(conn net.Conn) ([ ]byte, error) { defer conn.Close( )

result := bytes.NewBuffer(nil) var buf [512]byte for { n, err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil, err } } return result.Bytes( ), nil}

serialização de dados

A comunicação entre um cliente e um serviço requer a troca de dados. Este dados podem ser altamente estruturado, mas tem que ser serializado para o transporte. Este capítulo olha para as noções básicas de serialização e, em seguida, considera várias técnicas apoiadas Por GO APIs.

Um cliente e servidor precisam trocar informações através de mensagens. TCP e UDP fornecer os mecanismos de transporte para fazer isso. O dois processos também tem que ter um protocolo no lugar para que a troca de mensagens pode ocorrer de forma significativa.

As mensagens são enviadas através da rede como uma sequência de bytes, que não tem estrutura, exceto para um fluxo linear de bytes. Nós deve abranger as diversas possibilidades de mensagens e os protocolos que os definem no próximo capítulo. Neste capítulo, concentrar-se em um componente de mensagens os dados que são transferidos.

Um programa normalmente construir estruturas complexas de dados para armazenar o estado atual programa. Em conversa com um cliente remoto ou serviço, o programa será a tentativa de transferir tais

VISITE UMA IGREJA EVANGELICA

Page 69: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

estruturas de dados através da rede ou seja, fora do aplicativo do espaço de endereço próprio.Linguagens de programação usar dados estruturados, como

registros / estruturas registros variantes array tamanho fixo ou variável string tamanho fixo ou variável mesas por exemplo, arrays de registros

Estruturas não lineares, como Lista ligada circular Árvore binária Objetos com referências a outros objetos

Nenhum de IP, TCP ou UDP saber o significado de qualquer um desses tipos de dados. Tudo o que eles podem conter é uma sequência de bytes.

Assim, uma aplicação tem que publicando todos os dados em um fluxo de bytes, a fim de escrevê-lo, e deserialise o fluxo de bytes de volta em estruturas de dados adequadas ao lê-lo. Estas duas operações são conhecidas como mobilizar e unmarshalling respectivamente.

Por exemplo, considere o envio da seguinte tabela de comprimento variável de duas colunas de cadeias de comprimento variável:

Isto poderia ser realizado por várias maneiras. Por exemplo, suponhamos que é sabido que os dados vão ser um número desconhecido de linhas numa tabela de duas colunas. Em seguida, uma forma empacotada pode ser

3 / / 3 rows, 2 columns assumed4 fred / / 4 char string,col 110 programmer / / 10 char string,col 26 liping / / 6 char string, col 17 analyst / / 7 char string, col 28 sureerat / / 8 char string, col 17 manager / / 7 char string, col 2

Coisas de comprimento variável pode, alternativamente, ter seu comprimento indicado pela terminação lós com um valor de "ilegal", como '\ 0' para strings:

3fred\0programmer\0liping\0analyst\0sureerat\0manager\0

Alternativamente, pode ser conhecido que os dados são de uma tabela fixa de 3 filas de duas colunas de cadeias de comprimento 8 e 10 respectivamente. Em seguida, uma serialização pode ser

fred\0\0\0\0programmerliping\0\0analyst\0\0\0sureeratmanager\0\0\0

Qualquer um desses formatos é bom mas o protocolo de troca de mensagens deve especificar qual é utilizado, ou permitir que ele seja determinado a serialização de dados

VISITE UMA IGREJA EVANGELICA

Page 70: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

acordo mútuo

A seção anterior apresentou uma visão geral do problema de serialização de dados. Na prática, os pormenores podem ser consideravelmente mais complexa.

Por exemplo, considere a primeira possibilidade, mobilizar uma tabela para a corrente

34 fred10 programmer6 liping7 analyst8 sureerat7 manager

Muitas perguntas surgem. Por exemplo, quantas linhas são possíveis para a mesa ou seja, o quão grande um número inteiro que precisamos para descrever o tamanho da linha? Se for 255 ou menos, então um único byte vai fazer, mas se for mais, então pode ser necessário um curto, inteiro ou longo. Um semelhante problema ocorre para o comprimento de cada string. Com os próprios personagens, para o qual o conjunto de caracteres que eles pertencem? Bit ASCII de 7? 16 bit Unicode? A questão de conjuntos de caracteres é discutido em detalhe em um capítulo posterior.

A serialização acima é opaco ou implícita. Se os dados é codificado usando o formato acima, então não há nada no serializado dados para dizer como deve ser unmarshalled. O lado unmarshalling tem que saber exatamente como os dados são serializados, a fim de desempacota-lo corretamente. Por exemplo, se o número de linhas é empacotado como um número inteiro de oito bits, mas unmarshalled como um dezesseis bits número inteiro, então um resultado incorreto ocorrerá como o receptor tenta desempacotar 3 e 4 como um inteiro de dezesseis bits, e o recebimento programa Irá quase certamente falhar mais tarde.

Um método de serialização cedo conhecido é XDR (representação de dados externos) usado pelo RPC da Sun, mais tarde conhecido como ONC (Aberto Network Computing). XDR é definido pela RFC 1832 e é instrutivo ver como está especificação é preciso. Mesmo assim, é XDR tipo insegura inerentemente como dados serializados não contém informações de tipo. A correção de seu uso em ONC é assegurada principalmente por compiladores de código de geração, tanto para triagem e unmarshalling.

Go não contém suporte explícito para triagem ou unmarshalling dados serializados opacos. O pacote RPC em Go não usa XDR, mas usa a serialização "gob", descrito mais adiante neste capítulo.

dados autodescrevendo

Dados auto descritivo carrega digitar informações, juntamente com os dados. Por exemplo, os dados anteriores pode ter como codificado

table uint8 3 uint 2string uint8 4 [ ]byte fredstring uint8 10 [ ]byte programmerstring uint8 6 [ ]byte lipingstring uint8 7 [ ]byte analyststring uint8 8 [ ]byte sureeratstring uint8 7 [ ]byte manager

VISITE UMA IGREJA EVANGELICA

Page 71: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Claro que, uma codificação real não seria normalmente tão pesado e detalhado como no exemplo: inteiros pequenos seriam usados como marcadores de tipo e os dados inteiros que ser embalados em pequenos como uma array de byte possível. (XML fornece um contraexemplo, embora.). No entanto, o princípio é que o marshaller Irá gerar tais informações digite os dados serializados. O unmarshaller vai saber as regras de geração de tipo e será capaz de usá-lo para reconstruir a estrutura de dados correto.

ASN.1

Abstract Syntax Notation One (ASN.1) foi originalmente concebido em 1984 para a indústria de telecomunicações. ASN.1 é um complexo padrão, e um subconjunto do que é suportado pelo Go no pacote "ASN1". Baseia-se os dados serializados auto descritivos de dados complexos estruturas. Seu principal uso em sistemas de redes atuais é como a codificação de certificados X.509, que são muito utilizadas em sistemas de autenticação. O apoio em Go é baseado no que é necessário para ler e escrever certificados X.509.

Duas funções permitem empacotar e desempacotar dados func

func Marshal(val interface{ }) ([ ]byte, os.Error)func Unmarshal(val interface{ }, b [ ]byte) (rest [ ]byte, err os.Error)

/* ASN.1 */

package main

import ( "encoding/asn1" "fmt" "os")

func main( ) { mdata, err := asn1.Marshal(13) checkError(err)

var n int _, err1 := asn1.Unmarshal(mdata, &n) checkError(err1)

fmt.Println("After marshal/unmarshal: ", n)}

func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

O valor unmarshalled, é claro, 13.

Uma vez que nós nos movemos para além desta, as coisas ficam mais difíceis. Para gerenciar os tipos de dados mais complexos, temos que olhar mais de perto o estruturas de dados suportados pelo ASN.1, e como apoio ASN.1 é feito em Go.

Qualquer método de serialização será capaz de lidar com certos tipos de dados e não lidar com alguns outros. Assim, a fim de determinar o adequação de qualquer serialização como ASN.1, você tem que olhar para os possíveis tipos de dados suportados contra aqueles que você deseja usar em sua aplicação. Os seguintes tipos ASN.1 são tomadas a partir de http:/ /www.objsys.com/asn1tutorial/node4.html

VISITE UMA IGREJA EVANGELICA

Page 72: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Os tipos simples são

BOOLEAN: os valores das variáveis de dois estadosInteiro: os valores das variáveis inteiras ModeloBIT STRING: Modelo de dados binários de tamanho arbitrário Octeto STRING: dados binários modelo

cujo comprimento é um múltiplo de oito NULL: indica ausência efetiva de um elemento de sequênciaOBJETO identificador: Nome informações objetosREAL: modelo valores das variáveis reaisEnumerados: valores modelo de variáveis com pelo menos três estadosPERSONAGEM STRING: Modelos valores que são cadeias de caracteres fro

As cadeias de caracteres pode ser a partir de determinados conjuntos de caracteres.

E, estreitolmente, há os tipos estruturados:

SEQUENCE: Modelos uma coleção ordenada de variáveis de tipo diferenteSET: Modelar uma coleção não ordenada de variáveis de diferentes tiposSEQUENCE OF: Modelos uma coleção ordenada de variáveis de tipos diferentes do mesmo tipoSET OF: Modelo de uma coleção não ordenada de variáveis do mesmo tipoCHOICE: Especifique uma coleção de tipos distintos de que para escolher um tipoSELECTION: Selecione um tipo de componente de um tipo CHOICE especificadaANY: Ativar um aplicativo para especificar o tipo Nota: Qualquer um ASN.1 Estruturado Tipo obsoleta.

Foi substituído com X.680 Open Type.

Nem todos estes são suportados por Go. Nem todos os valores possíveis são suportados por Go. As regras como dadas no pacote Go "ASN1" documentação são

Um INTEGER ASN.1 pode ser escrito para um int ou int64. Se o valor codificado não se encaixa no tipo Go, Unmarshal retorna um

Analisar erro. Uma STRING ASN.1 BIT podem ser gravados em um bitstring. Um octeto STRING ASN.1 podem ser gravados em um byte [ ]. Um objeto identificador ASN.1 podem ser gravados em um ObjectIdentifier. Um ASN.1 enumerados podem ser gravados em um enumerado. Um UTCTime ASN.1 ou GeneralizedTime pode ser escrito para a * time.time. Um PrintableString ASN.1 ou IA5String podem ser gravados em um string. Qualquer um dos valores ASN.1 acima pode ser escrito para uma interface { }. O valor armazenado

na interface tem o correspondente Go digita. Para inteiros, que tipo for int64. Uma sequência de ASN.1 DE x ou conjunto de x pode ser escrito para uma slice se um x pode ser

escrito com o tipo de elemento da slice. Uma sequência de ASN.1 ou SET pode ser gravado em um struct se cada um dos elementos na sequência pode ser escrito para o elemento na estrutura correspondente.

Go coloca restrições reais em ASN.1. Por exemplo, permite ASN.1 inteiros de qualquer tamanho, embora a aplicação Vai só permitIrá até assinado inteiros de 64 bits. Por outro lado, Go distingue entre tipos assinados e não assinados, enquanto ASN.1 não. Assim, para exemplo, a transmissão de um valor de uint64 pode falhar se ele é muito grande para int64, Na mesma linha, ASN.1 permite que vários conjuntos de caracteres diferentes. Go só suporta PrintableString e IA5String (ASCII). ASN.1 não suporta caracteres Unicode (que requerem a extensão ASN.1 BMPString). O conjunto de caracteres Unicode básico de Go é não suportados, e se um aplicativo exige transporte de caracteres Unicode, então uma codificação como UTF7 será necessário.

Essas codificações são discutidas em um capítulo posterior sobre conjuntos de caracteres.Vimos que um valor como um inteiro pode ser facilmente empacotado e unmarshalled. Outros tipos

básicos como booleanos e reais podem ser tratados de forma semelhante. Strings que são compostos inteiramente de caracteres ASCII pode ser empacotado e unmarshalled.

No entanto, se a cadeia é, por exemplo, "Olá \ u00bc", que contém o caractere nãoASCII '1⁄4 ", então ocorrerá um erro:" ASN.1 erro estrutura: PrintableString contém caractere inválido "Esse código funciona, desde que a string só é composta de impressão, caracteres:

VISITE UMA IGREJA EVANGELICA

Page 73: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

s := "hello"mdata, _ := asn1.Marshal(s)var newstr stringasn1.Unmarshal(mdata, &newstr)

ASN.1 também inclui alguns "tipos úteis" e não na lista acima, como a hora UTC. Go suporta este tipo de tempo UTC. Isto significa que você pode passar valores de tempo de uma forma que não é possível para outros valores de dados. O ASN.1 não suporta ponteiros, mas Go tem especial código para gerenciar ponteiros para valores de tempo. A função returm. O código especial empacota isso, e pode

GetLocalTime * Time.time ser unmarshalled em uma variável ponteiro para um time.time objeto. Assim, este código funciona

t := time.LocalTime( )mdata, err := asn1.Marshal(t)var newtime = new(time.Time)_, err1 := asn1.Unmarshal(&newtime, mdata)

Tanto LocalTime e new lida com ponteiros para um * Time.time. E Go cuida este caso especial.

Em geral, você provavelmente vai querer empacotar e desempacotar estruturas. Para além do caso especial de tempo, Go terá todo o prazer lidar com estruturas, mas não com ponteiros para estruturas. Operações como criar ponteiros, então você tem que excluir a referência a eles new antes de triagem / unmarshalling eles. Vá normalmente diferentes ponteiros para você quando necessário, mas não neste caso. Estes dois trabalhar para um tipo de T:

/ / using variablesvar t1 Tt1 = ...mdata1, _ := asn1.Marshal(t)var newT1 Tasn1.Unmarshal(&newT1, mdata1)/ // using pointersvar t2 = new(T)*t2 = ...mdata2, _ := asn1.Marshal(*t2)var newT2 = new(T)asn1.Unmarshal(newT2, mdata2)

Qualquer combinação adequada de indicadores e variáveis vai funcionar tão bem.Os campos de uma estrutura devem ser todos exportável, ou seja, os nomes de campo deve começar

com uma letra maiúscula. Go usa a refletir pacote para empacotar / desempacotar as estruturas, por isso deve ser capaz de examinar todos os campos. Este tipo não pode ser empacotado:

type T struct { Field1 int field2 int / / not exportable }

ASN.1 só lida com os tipos de dados. Não considera os nomes dos campos de estrutura. Então, o seguinte tipo de T1pode ser marshalled / unmarshalled em tipo T2como os campos correspondentes são os mesmos tipos:

type T1 struct { F1 int F2 string}

VISITE UMA IGREJA EVANGELICA

Page 74: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

type T2 struct { FF1 int FF2 string}

Não só os tipos de cada campo deve corresponder, mas o número deve corresponder também. Esses dois tipos não funcionam:

type T1 struct { F1 int}

type T2 struct { F1 int F2 string / / too many fields}

Cliente e servidor ASN.1

Agora (estreitolmente) voltemos a usar ASN.1 para o transporte de dados através da rede.Podemos escrever um servidor TCP que fornece a hora atual como um tipo ASN.1 Tempo, usando as

técnicas do último capítulo. A servidor está

/* ASN1 DaytimeServer */package main

import ( "encoding/asn1" "fmt" "net" "os" "time")

func main( ) {

service := ":1200" tcpAddr, err := net.ResolveTCPAddr("tcp", service) checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { conn, err := listener.Accept( ) if err != nil { continue }

daytime := time.Now( ) / / Ignore return network errors. mdata, _ := asn1.Marshal(daytime) conn.Write(mdata) conn.Close( ) / / we're finished }}

func checkError(err error) {

VISITE UMA IGREJA EVANGELICA

Page 75: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

o que pode ser compilado para um arquivo executável como e executar sem argumentos. Ele vai esperar por conexões e ASN1DaytimeServer em seguida, enviar o tempo como uma sequência de ASN.1 para o cliente.

Um cliente é

/* ASN.1 DaytimeClient*/package main

import ( "bytes" "encoding/asn1" "fmt" "io" "net" "os" "time")

func main( ) { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0]) os.Exit(1) } service := os.Args[1]

conn, err := net.Dial("tcp", service) checkError(err)

result, err := readFully(conn) checkError(err)

var newtime time.Time _, err1 := asn1.Unmarshal(result, &newtime) checkError(err1) fmt.Println("After marshal/unmarshal: ", newtime.String( ))

os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) }}

func readFully(conn net.Conn) ([ ]byte, error) { defer conn.Close( )

result := bytes.NewBuffer(nil) var buf [512]byte for {

VISITE UMA IGREJA EVANGELICA

Page 76: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

n, err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil, err } } return result.Bytes( ), nil}

Este se conecta ao serviço prestado de uma forma como local host: 1200, Lê o pacote TCP e decodifica o conteúdo ASN.1 volta em uma string, que ele imprime.

Devemos notar que nenhum destes dois o cliente ou o servidor são compatível com os clientes baseados em texto e servidores da último capítulo. Este cliente e servidor estão trocando ASN.1 codificado valores de dados, e não strings textuais.

JSON

JSON significa JavaScript Object Notation. Ele foi projetado para ser um meio lighweight de passar dados entre Java Script sistemas. Ele usa um formato baseado em texto e é suficientemente geral que se tornou usado como um método de serialização de propósito geral para muitas linguagens de programação.

JSON serializa objetos, arrays e valores básicos. Os valores básicos incluem sequência, número, valores booleanos e valor nulo. Arrays são uma lista de valores que podem representar arrays, vetores, listas ou sequências de várias linguagens de programação, separados por vírgulas.

Eles são delimitados por colchetes "[...]". Os objetos são representados por uma lista de "campo: valor" pares entre chaves "{... } ".

Por exemplo, a tabela de funcionários dadas anteriormente pode ser escrito como uma array de objetos de funcionários:

[{Name: fred, Occupation: programmer},{Name: liping, Occupation: analyst},{Name: sureerat, Occupation: manager}]

Não há nenhum suporte especial para tipos de dados complexos, tais como datas, não há distinção entre os tipos de números, nenhum tipo recursivas, etc

JSON é uma linguagem muito simples, mas, no entanto, pode ser bastante útil. Seu formato baseado em texto torna mais fácil para as pessoas usarem, mesmo embora tenha as despesas gerais de manipulação de strings.

A partir da especificação do pacote Go JSON, triagem usa as seguintes codificações padrão dependente do tipo:

Os valores booleanos codificar como booleanos JSON. Valores de ponto flutuante e inteiros codificar como números de JSON. Valores String codificar como strings JSON, com cada sequência UTF8 inválida substituída pela

codificação do Unicode caráter de substituição U + FFFD. Valores da array e slice codificar como arrays JSON, só que [ ] byte codifica como uma sequência

codificada em base64. Valores struct codificar como objetos JSON. Cada campo de struct torna-se um membro do objeto.

Por padrão nome da chave do objeto é o nome do campo struct convertida em minúsculas. Se o campo de estrutura tem uma etiqueta, essa etiqueta será utilizado como o nome em vez disso.

Valores Mapa codificar como objetos JSON. Tipo de chave do mapa deve ser string; as chaves de objeto são usados diretamente como chaves do mapa.

Valores de ponteiro como codificar o valor apontado. (Nota: isto permite que a árvore, mas não gráficos!). Um ponteiro nulo codifica como o nulo JSON objeto.

Valores de interface como codificar o valor contido na interface. A interface valor nulo codifica como

VISITE UMA IGREJA EVANGELICA

Page 77: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

o objeto JSON nulo. Canal, complexas e função valores não podem ser codificados em JSON. A tentativa de codificar um

tal valor provoca Marshal retornar um InvalidTypeError. JSON não pode representar estruturas de dados cíclicos e não Marshal não lidar com eles.

Passando estruturas cíclicas ao marechal vai resultar em uma recursão infinita.

Um programa para armazenar JSON dados serializados em um arquivo é

/* SaveJSON */

package main

import ( "encoding/json" "fmt" "os")

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}

type Email struct { Kind string Address string}

func main( ) { person := Person{ Name: Name{Family: "Newmarch", Personal: "Jan"}, Email: [ ]Email{Email{Kind: "home", Address: "[email protected]"}, Email{Kind: "work", Address: "[email protected]"}}}

saveJSON("person.json", person)}

func saveJSON(fileName string, key interface{ }) { outFile, err := os.Create(fileName) checkError(err) encoder := json.NewEncoder(outFile) err = encoder.Encode(key) checkError(err) outFile.Close( )}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

E carregá-lo de volta na memória é

VISITE UMA IGREJA EVANGELICA

Page 78: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

/* LoadJSON */

package main

import ( "encoding/json" "fmt" "os")

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}

type Email struct { Kind string Address string}

func (p Person) String( ) string { s := p.Name.Personal + " " + p.Name.Family for _, v := range p.Email { s += "\n" + v.Kind + ": " + v.Address } return s}func main( ) { var person Person loadJSON("person.json", &person)

fmt.Println("Person", person.String( ))}

func loadJSON(fileName string, key interface{ }) { inFile, err := os.Open(fileName) checkError(err) decoder := json.NewDecoder(inFile) err = decoder.Decode(key) checkError(err) inFile.Close( )}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

É serializado para

VISITE UMA IGREJA EVANGELICA

Page 79: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

{"Name":{"Family":"Newmarch", "Personal":"Jan"}, "Email":[{"Kind":"home","Address":"[email protected]"}, {"Kind":"work","Address":"[email protected]"} ]}

Um cliente e servidor

Um cliente para enviar dados de uma pessoa e lê-lo de volta dez vezes é

/* JSON EchoClient*/package main

package main

import ( "fmt" "net" "os" "encoding/json" "bytes" "io")

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}

type Email struct { Kind string Address string}

func (p Person) String( ) string { s := p.Name.Personal + " " + p.Name.Family for _, v := range p.Email { s += "\n" + v.Kind + ": " + v.Address } return s}

func main( ) { person := Person{ Name: Name{Family: "Newmarch", Personal: "Jan"}, Email: [ ]Email{Email{Kind: "home", Address: "[email protected]"}, Email{Kind: "work", Address: "[email protected]"}}}

if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } service := os.Args[1]

VISITE UMA IGREJA EVANGELICA

Page 80: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

conn, err := net.Dial("tcp", service) checkError(err)

encoder := json.NewEncoder(conn) decoder := json.NewDecoder(conn)

for n := 0; n < 10; n++ { encoder.Encode(person) var newPerson Person decoder.Decode(&newPerson) fmt.Println(newPerson.String( )) }

os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

func readFully(conn net.Conn) ([ ]byte, error) { defer conn.Close( )

result := bytes.NewBuffer(nil) var buf [512]byte for { n, err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil, err } } return result.Bytes( ), nil}

E o servidor correspondente

/* JSON EchoServer */package main

import ( "fmt" "net" "os" "encoding/json")

type Person struct { Name Name Email [ ]Email}

VISITE UMA IGREJA EVANGELICA

Page 81: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

type Name struct { Family string Personal string}

type Email struct { Kind string Address string}

func (p Person) String( ) string { s := p.Name.Personal + " " + p.Name.Family for _, v := range p.Email { s += "\n" + v.Kind + ": " + v.Address } return s}

func main( ) {

service := "0.0.0.0:1200" tcpAddr, err := net.ResolveTCPAddr("tcp", service) checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { conn, err := listener.Accept( ) if err != nil { continue }

encoder := json.NewEncoder(conn) decoder := json.NewDecoder(conn)

for n := 0; n < 10; n++ { var person Person decoder.Decode(&person) fmt.Println(person.String( )) encoder.Encode(person) } conn.Close( ) / / we're finished}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

O pacote gob

Gob é uma técnica de serialização específico para Go. Ele é projetado para codificar Go tipos de dados específica e não dispõe atualmente de apoio ou por qualquer outro idioma. Ele suporta todos os tipos de dados Go, exceto para os canais, funções e interfaces. Ele suporta inteiros de todos os tipos e tamanhos, strings e booleanos, estruturas, arrays e slices. Actualmente, tem alguns problemas com circular estruturas, tais como anéis, mas que vai melhorar com o tempo.

VISITE UMA IGREJA EVANGELICA

Page 82: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Gob codifica digitar informações em suas formas serializados. Isto é muito mais extensa do que o tipo de informação em dizer um X.509 serialização, mas muito mais eficiente do que o tipo de informação contida em um documento XML. Digite as informações está incluído apenas uma vez por cada segmento de dados, mas inclui, por exemplo, os nomes dos campos struct.

Esta inclusão de informações sobre o tipo faz Gob triagem e unmarshalling bastante robusto para mudanças ou diferenças entre o marshaller e unmarshaller. Por exemplo, uma estrutura

struct T {a intb int}

Pode ser empacotado e depois unmarshalled em uma estrutura diferente

struct T {b inta int}

Onde a ordem dos campos mudou. Ele também pode lidar com campos faltantes (os valores são ignorados) ou campos extras (os campos são deixados inalterado). Pode lidar com tipos de ponteiro, de modo que a estrutura acima poderia ser em

struct T {*a int**b int}

Até certo ponto, ele pode lidar com o tipo de coerção para que um int campo pode ser ampliado em um int64 , Mas não com incompatível tipos, tais como int e uint.

Para usar Gob para marshall um valor de dados, você primeiro precisa criar uma . Isso leva um Escritor como parâmetro e empacotamento será eito para este fluxo de gravação. O codificador tem um método Codificar

Marshalls que o valor para o fluxo. Este método pode ser chamado várias vezes em várias partes de dados. Digite as informações para cada tipo de dados só é escrito uma vez, no entanto.

Você usa um para desempacotar o fluxo de dados em série. Isso leva umDecoderLeitor e cada leitura retorna uma dados unmarshalled valor.Um programa para armazenar dados gob serializados em um arquivo é

/* SaveGob */

package main

import ( "fmt" "os" "encoding/gob")

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}

VISITE UMA IGREJA EVANGELICA

Page 83: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

type Email struct { Kind string Address string}

func main( ) { person := Person{ Name: Name{Family: "Newmarch", Personal: "Jan"}, Email: [ ]Email{Email{Kind: "home", Address: "[email protected]"}, Email{Kind: "work", Address: "[email protected]"}}}

saveGob("person.gob", person)}

func saveGob(fileName string, key interface{ }) { outFile, err := os.Create(fileName) checkError(err) encoder := gob.NewEncoder(outFile) err = encoder.Encode(key) checkError(err) outFile.Close( )}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

E carregá-lo de volta na memória é

package main

import ( "fmt" "os" "encoding/gob")

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}

type Email struct { Kind string Address string}

func (p Person) String( ) string { s := p.Name.Personal + " " + p.Name.Family for _, v := range p.Email { s += "\n" + v.Kind + ": " + v.Address

VISITE UMA IGREJA EVANGELICA

Page 84: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

} return s}func main( ) { var person Person loadirb("person.gob", &person)

fmt.Println("Person", person.String( ))}

func loadirb(fileName string, key interface{ }) { inFile, err := os.Open(fileName) checkError(err) decoder := gob.NewDecoder(inFile) err = decoder.Decode(key) checkError(err) inFile.Close( )}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Um cliente e servidor

Um cliente para enviar dados de uma pessoa e lêlo de volta dez vezes é

/* Gob EchoClient*/

package main

import ( "fmt" "net" "os" "encoding/gob" "bytes" "io")

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}

type Email struct { Kind string Address string}

func (p Person) String( ) string {

VISITE UMA IGREJA EVANGELICA

Page 85: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

s := p.Name.Personal + " " + p.Name.Family for _, v := range p.Email { s += "\n" + v.Kind + ": " + v.Address } return s}

func main( ) { person := Person{ Name: Name{Family: "Newmarch", Personal: "Jan"}, Email: [ ]Email{Email{Kind: "home", Address: "[email protected]"}, Email{Kind: "work", Address: "[email protected]"}}}

if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } service := os.Args[1]

conn, err := net.Dial("tcp", service) checkError(err)

encoder := gob.NewEncoder(conn) decoder := gob.NewDecoder(conn)

for n := 0; n < 10; n++ { encoder.Encode(person) var newPerson Person decoder.Decode(&newPerson) fmt.Println(newPerson.String( )) }

os.Exit(0)}

}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

func readFully(conn net.Conn) ([ ]byte, error) { defer conn.Close( )

result := bytes.NewBuffer(nil) var buf [512]byte for { n, err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil, err } } return result.Bytes( ), nil}

VISITE UMA IGREJA EVANGELICA

Page 86: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

e o correspondente ao servidor é

/* Gob EchoServer */package main

import ( "fmt" "net" "os" "encoding/gob")

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}

type Email struct { Kind string Address string}

func (p Person) String( ) string { s := p.Name.Personal + " " + p.Name.Family for _, v := range p.Email { s += "\n" + v.Kind + ": " + v.Address } return s}

func main( ) {

service := "0.0.0.0:1200" tcpAddr, err := net.ResolveTCPAddr("tcp", service) checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { conn, err := listener.Accept( ) if err != nil { continue }

encoder := gob.NewEncoder(conn) decoder := gob.NewDecoder(conn)

for n := 0; n < 10; n++ { var person Person decoder.Decode(&person) fmt.Println(person.String( )) encoder.Encode(person)

VISITE UMA IGREJA EVANGELICA

Page 87: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

} conn.Close( ) / / we're finished }}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Codificação de dados binários como strings

Era uma vez, transmtting dados de 8 bits era problemático. Foi muitas vezes transmitida através de linhas seriais ruidosos e poderia facilmente tornar-se corrompido. Dados de 7 bits, por outro lado, pode ser transmitida de forma mais fiável porque o 8o bit pode ser usado como o dígito de verificação. Para exemplo, em um esquema de "paridade", o dígito de verificação seria definida como um ou zero para fazer um número par de 1s em um byte. Este permite a detecção de erros de um único bit de cada byte.

ASCII é um conjunto de caracteres de 7 bits. Um número de esquemas foram desenvolvidos que são mais sofisticados do que simples paridade verificação, mas que envolvem a tradução de dados binários de 8 bits em formato ASCII de 7 bits. Essencialmente, os dados de 8 bits está estendida em alguns caminho ao longo dos bytes de 7 bits.

Dados binários transmitidos em respostas HTTP e solicitações é muitas vezes traduzido em uma forma ASCII. Isto torna mais fácil para inspecionar o Mensagens HTTP com um leitor de texto simples, sem se preocupar com o que estranhos bytes de 8 bits pode fazer para o seu monitor!

Um formato comum é Base64. Go tem suporte para vários formatos binários para texto, incluindo base64.

Existem duas funções principais a serem usadas para a codificação e decodificação Base64:

func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloserfunc NewDecoder(enc *Encoding, r io.Reader) io.Reader

Um programa simples, apenas para codificar e decodificar um conjunto de oito dígitos binários é

/** * Base64 */

package main

import ( "bytes" "encoding/base64" "fmt")

func main( ) {

eightBitData := [ ]byte{1, 2, 3, 4, 5, 6, 7, 8} bb := &bytes.Buffer{ } encoder := base64.NewEncoder(base64.StdEncoding, bb) encoder.Write(eightBitData) encoder.Close( ) fmt.Println(bb)

dbuf := make([ ]byte, 12) decoder := base64.NewDecoder(base64.StdEncoding, bb) decoder.Read(dbuf)

VISITE UMA IGREJA EVANGELICA

Page 88: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

for _, ch := range dbuf { fmt.Print(ch) }}

Protocolos de nível de aplicativo

Um cliente e um servidor trocam mensagens que consistem em tipos de mensagens e mensagens dados. Isso requer um projeto de um protocolo de troca de mensagens adequado. Este capítulo analisa algumas das questões envolvidas nisso, e dá um exemplo completo de um aplicação cliente servidor simples.

Um cliente e servidor precisam trocar informações através de mensagens. TCP e UDP fornecer os mecanismos de transporte para fazer isso. Os dois processos também precisam ter um protocolo no lugar para que a troca de mensagens pode ocorrer de forma significativa. Um protocolo define que tipo de conversa pode ocorrer entre dois componentes de uma aplicação distribuída, especificando as mensagens, dados tipos de formatos de codificação, e assim por diante.

Protocolo de Projeto

Há muitas possibilidades e questões a serem decididas na concepção de um protocolo. Algumas das questões incluem:

Será que é para ser transmitido ou ponto a ponto? Transmissão deve ser UDP, multicast local ou o MBONE mais experimental. Ponto a ponto poderia

ser TCP ou UDP. É para ser stateful vs apátrida? É razoável para um lado para manter o estado sobre o outro lado? Muitas vezes, é mais simples de

fazê-lo, mas o que acontece se algo falhar? É o protocolo de transporte confiável ou não confiável? Confiança é muitas vezes mais lento, mas

então você não precisa se preocupar tanto com mensagens perdidas. São respostas necessárias? Se for necessária uma resposta, como você lida com uma resposta

perdida? Pode ser usado Tempos limite. O formato de dados que você quer? Duas possibilidades comuns são MIME ou codificação byte. É o

seu fluxo de comunicação em rajadas ou estável? Ethernet e a Internet são os melhores em tráfego em rajadas. Fluxo constante é necessário para

streams de vídeo e, particularmente, para a voz. Se necessário, como você administra Qualidade de Serviço (QoS)?

Existem vários fluxos com a sincronização necessária? Será que os dados precisam ser sincronizados com alguma coisa? por exemplo, vídeo e voz.

Você está construindo um aplicativo independente ou uma biblioteca para ser usado por outras pessoas? Os padrões de documentação necessária pode variar.

O controle de versão

Um protocolo usado em um sistema cliente / servidor Irá evoluir ao longo do tempo, mudando como o sistema se expande. Isto levanta a compatibilidade problemas: um cliente da versão 2 Irá fazer pedidos que uma versão um servidor não entendem, enquanto que um servidor da versão 2 Irá enviar responde que um cliente da versão 1 não vai entender.

Cada lado deve, idealmente, ser capaz de compreender as mensagens para a sua própria versão e todos os anteriores. Deve ser capaz de escrever para respostas consultas de estilo antirá em formato de resposta de estilo antirá.

VISITE UMA IGREJA EVANGELICA

Page 89: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

A capacidade de falar formatos de versões anteriores podem ser perdidos se o protocolo muda muito. Neste caso, você precisa ser capaz de garantir que nenhuma cópia da versão anterior ainda existem e que geralmente é impossível.

Parte da configuração do protocolo deve envolver informações sobre a versão.

A Web

A Web é um bom exemplo de um sistema que é confuso por diferentes versões. O protocolo tem sido através de três versões, e a maioria dos servidores / navegadores agora usar a versão mais recente. A versão é dada em cada pedido

Mas o conteúdo das mensagens tem sido através de um grande número de versões:

Versões HTML 14 (todos diferentes), com a versão 5 no horizonte; etiquetas fora do padrão reconhecido por diferentes navegadores; Documentos não HTML muitas vezes exigem manipuladores de conteúdo que pode ou não estar

presente se seu navegador tem um manipulador para Flash? Tratamento inconsistente de conteúdo do documento (por exemplo, alguns conteúdos de estilo Irá

falhar alguns navegadores) Suporte diferente para Java Script (e versões diferentes de Java Script) Motores de tempo de execução diferentes para Java Muitas páginas não se conformam com qualquer versões HTML (por exemplo, com erros de sintaxe)

Message Format

No último capítulo, discutimos algumas possibilidades para a representação de dados a serem enviados através do fio. Agora vamos olhar para um nível acima, a as mensagens que podem conter tais dados.

O cliente e servidor Irá trocar mensagens com diferentes significados. Ex: Solicitação de login, Obter pedido de registro, Sessão de resposta, Registro de resposta de dados.

O cliente Irá preparar um pedido que deve ser entendida pelo servidor. O servidor Irá preparar uma resposta que deve ser entendido pelo cliente.

Geralmente, a primeira parte da mensagem será um tipo de mensagem.

Cliente para o servidor

VISITE UMA IGREJA EVANGELICA

Page 90: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

LOGIN name passwdGET cpe4001 grade

Servidor para o cliente

LOGIN succeededGRADE cpe4001 D

Os tipos de mensagens podem ser strings ou inteiros. Por exemplo, HTTP utiliza números inteiros, como 404 para significar "não encontrado" (embora estes números inteiro são escritos como strings). As mensagens do cliente para o servidor e vice-versa são disjuntos: "LOGIN" do cliente para o servidor é diferente "Login" do servidor para o cliente.

Formato de dados

Há duas opções de formato para mensagens principais: byte codificado ou caracteres codificado.

Formato Byte

No formato de byte a primeira parte da mensagem é tipicamente um byte para distinguir entre tipos de mensagem.

O manipulador de mensagem seria examinar este primeiro byte para distinguir o tipo de mensagem e, em seguida, executar um switch para selecionar o manipulador apropriado para esse tipo.

Mais bytes na mensagem deve conter o conteúdo da mensagem de acordo com um formato predefinido (como discutido no precedente capítulo).

As vantagens são densidade e, portanto, a velocidade. As desvantagens são causadas pela opacidade dos dados: pode ser mais difícil de detectar erros, mais difícil de debug, exigem funções especiais propósito de decodificação. Há muitos exemplos de byte codificado formatos, incluindo os principais protocolos, como DNS e NFS, upto os recentes, como o Skype. Claro, se o seu protocolo não é especificados publicamente, então um formato de byte podem também tornar mais difícil para os outros a fazer engenharia reversait!

Pseudocódigo para um servidor byte formato é

handleClient(conn) {while (true) {byte b = conn.readByte( )switch (b) {case MSG_1: ...case MSG_2: ......}}}

Go tem suporte básico para o gerenciamento de fluxos de bytes. A interfaceConn tem métodos

(c Conn) Read(b [ ]byte) (n int, err os.Error)(c Conn) Write(b [ ]byte) (n int, err os.Error)e estes métodos são implementados pelos UDPConn e Tcpconn .

Formato de caractere

Neste modo, tudo é enviado como caracteres, se possível. Por exemplo, um inteiro 234 seriam enviados como, por exemplo, os três personagens

VISITE UMA IGREJA EVANGELICA

Page 91: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

'2 ', '3' E '4 'ao invés de um byte 234. Dados que é inerentemente binário pode ser codificado base64 para transformá-lo em um formato de 7 bits e, em seguida, enviado como caracteres ASCII, como discutido no capítulo anterior.

Em formato de caractere,

A mensagem é uma sequência de uma ou mais linhas.O início da primeira linha da mensagem é tipicamente uma palavra que representa o tipo de

mensagem. Funções de manipulação de string pode ser usado para decodificar o tipo de mensagem e dados. O resto da primeira linha e linhas sucessivas contêm os dados. Funções orientadas para a linha e convenções orientada de linha são usados para gerenciar isso.

Pseudocódigo é

handleClient(conn) { while (true) { byte b = conn.readByte( ) switch (b) { case MSG_1: ... case MSG_2: ... ... } } }

Formatos de caracteres são mais fáceis de configurar e mais fácil de depurar. Por exemplo, você pode usar telnet para se conectar a um servidor em qualquer porta, e enviar as solicitações do cliente para o servidor. Não é tão fácil para o outro lado, mas você pode usar ferramentas como para espionar o tráfego TCP

tcpdump e ver imediatamente o que os clientes estão enviando para os servidores.Não há o mesmo nível de suporte em Go para o gerenciamento de fluxos de caracteres. Há

problemas significativos com conjuntos de caracteres e codificações de caracteres, e vamos explorar estas questões em um capítulo posterior.

Se nós apenas fingir que está tudo ASCII, como se fosse mais um momento, então formatos de caracteres são bastante simples de lidar.

A principal complicação a este nível é o estado variando de "nova linha" em diferentes sistemas operacionais. Unix utiliza o único caractere '\ n'. O Windows e outros (mais corretamente) usar o par de "\ r \ n". Na internet, o par "\ r \ n" é o mais comum Unix sistemas só precisa tomar cuidado para que eles não assumem '\ n'.

Exemplo Simples

Este exemplo trata de um protocolo de pesquisa em diretório basicamente uma versão simplificada do FTP, mas, mesmo sem a transferência de arquivos parte. Nós só considerar listando um nome de diretório, listar o conteúdo de um diretório e mudar o diretório atual tudo sobre o lado do servidor, é claro. Este é um exemplo trabalhado completa de criação de todos os componentes de uma aplicação cliente servidor. É uma simples programa que inclui mensagens em ambos os sentidos, assim como o projeto de protocolo de mensagens.

Olhe para um programa não cliente servidor simples que permite listar arquivos em um diretório e alterar e imprimir o diretório no servidor. Nós omitir copiar arquivos, como que aumenta a duração do programa, sem realmente a introdução de conceitos importantes. Para simplicidade, todos os nomes de arquivo será assumida para a 7bit ASCII. Se nós apenas olhou para um aplicativo independente em primeiro lugar, em seguida, o pseudocódigo seria

read line from userwhile not eof do if line == dir list directory

VISITE UMA IGREJA EVANGELICA

Page 92: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

else

if line == cd <dir> change directory else

if line == pwd print directory else

if line == quit quit else complain

read line from user

A aplicação não distribuída seria apenas vincular o código UI e arquivo de acesso

Em uma situação de cliente servidor, o cliente seria para o usuário estreitol, conversando com um servidor em outro lugar. Aspectos deste programa pertencem somente no estreitol de apresentação, tais como a obtenção dos comandos do usuário. Algumas são mensagens do cliente para o servidor, alguns são apenas no estreitol do servidor.

Para um navegador de diretórios simples, suponha que todos os diretórios e arquivos estão no estreitol do servidor, e estamos apenas transferindo arquivo a informação a partir do servidor para o cliente. O lado do cliente (incluindo aspectos de apresentação) vai se tornar

read line from userwhile not eof do if line == dir list directory else

if line == cd <dir> change directory else

VISITE UMA IGREJA EVANGELICA

Page 93: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

if line == pwd print directory else

if line == quit quit else complain

read line from user

em que as linhas em itálico envolvem a comunicação com o servidor.

Aspectos alternativos de apresentação

Um programa GUI permitiria conteúdo do diretório a ser exibido como listas, para que os arquivos sejam selecionados e ações como alterar diretório pelo que pode ser realizado sobre eles. O cliente seria controlada por ações associadas a vários eventos que acontecem em gráfica objetos. O pseudocódigo pode parecer

change dir button: if there is a selected file change directory if successful update directory label list directory update directory list

As funções chamadas a partir da interface do usuário diferente deve ser o mesmo mudando apresentação não deve alterar o código de rede

Protocolo informal

client request server response

dir send list of files

cd <dir>change dirsend error if failedsend ok if succeed

pwd send current directory

quit quit

Protocolo Texto

Este é um protocolo simples. A estrutura de dados mais complicado que temos de enviar é uma array de sequências de caracteres para uma listagem de diretório.

Neste caso, não precisa dos pesados Técnicas dever de serialização do último capítulo. Neste caso, podemos usar um formato de texto

simples.

Em Mas, mesmo se fizermos o protocolo simples, nós ainda temos que especificá-lo em detalhes. Nós escolhemos o formato da mensagem seguinte:

Todas as mensagens são em 7bit USASCII

VISITE UMA IGREJA EVANGELICA

Page 94: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

As mensagens são casesensitive. Cada mensagem é composta por uma sequência de linhas A primeira palavra na primeira linha de cada mensagem descreve o tipo de mensagem. Todas as outras palavras são os dados da mensagem Todas as palavras são separadas por exatamente um caractere de espaço Cada linha é denunciado por CRLF

Algumas das escolhas feitas acima são mais fracos em protocolos reais. Por exemplo

Tipos de mensagens poderia ser caseinsensitive. Isso só requer mapeamento de tipo de mensagem de strings para baixo para minúsculas antes decodificação

Uma quantidade arbitrária de espaço em branco poderia ser deixado entre as palavras. Isso só acrescenta um pouco mais de complicação, comprimindo branco espaço

Caracteres de continuação, como '\' pode ser usado para quebrar linhas longas ao longo de várias linhas. Isto começa a fazer um processamento mais complexo

Apenas uma '\ n' pode ser utilizado como linha de terminador, bem como '\ r \ n'. Isso faz com que o reconhecimento estreitol da linha um pouco mais difícil

Todas estas variações existir em protocolos reais. Cumulativamente, eles fazem o processamento de strings apenas mais complexa do que no nosso caso.

client request server response

send "DIR"send list of files, one per lineterminated by a blank line

send "CD <dir>"change dirsend "ERROR" if failedsend "OK"

send "PWD" send current working directory

Código do servidor

/* FTP Server */package main

import ( "fmt" "net" "os")const ( DIR = "DIR" CD = "CD" PWD = "PWD")

func main( ) {

service := "0.0.0.0:1202" tcpAddr, err := net.ResolveTCPAddr("tcp", service) checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

VISITE UMA IGREJA EVANGELICA

Page 95: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

for { conn, err := listener.Accept( ) if err != nil { continue } go handleClient(conn) }}

func handleClient(conn net.Conn) { defer conn.Close( )

var buf [512]byte for { n, err := conn.Read(buf[0:]) if err != nil { conn.Close( ) return }

s := string(buf[0:n]) / / decode request if s[0:2] == CD { chdir(conn, s[3:]) } else if s[0:3] == DIR { dirList(conn) } else if s[0:3] == PWD { pwd(conn) }

}}

func chdir(conn net.Conn, s string) { if os.Chdir(s) == nil { conn.Write([ ]byte("OK")) } else { conn.Write([ ]byte("ERROR")) }}

func pwd(conn net.Conn) { s, err := os.Getwd( ) if err != nil { conn.Write([ ]byte("")) return } conn.Write([ ]byte(s))}

func dirList(conn net.Conn) { defer conn.Write([ ]byte("\r\n"))

dir, err := os.Open(".") if err != nil { return }

names, err := dir.Readdirnames(-1) if err != nil { return

VISITE UMA IGREJA EVANGELICA

Page 96: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

} for _, nm := range names { conn.Write([ ]byte(nm + "\r\n")) }}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Lista do cliente

/* FTPClient */package main

import ( "fmt" "net" "os" "bufio" "strings" "bytes")

/ / strings used by the user interfaceconst ( uiDir = "dir" uiCd = "cd" uiPwd = "pwd" uiQuit = "quit")

/ / strings used across the networkconst ( DIR = "DIR" CD = "CD" PWD = "PWD")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host") os.Exit(1) }

host := os.Args[1]

conn, err := net.Dial("tcp", host+":1202") checkError(err)

reader := bufio.NewReader(os.Stdin) for { line, err := reader.ReadString('\n') / / lose trailing whitespace

VISITE UMA IGREJA EVANGELICA

Page 97: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

line = strings.TrimRight(line, " \t\r\n") if err != nil { break }

/ / split into command + arg strs := strings.SplitN(line, " ", 2) / / decode user request switch strs[0] { case uiDir: dirRequest(conn) case uiCd: if len(strs) != 2 { fmt.Println("cd <dir>") continue } fmt.Println("CD \"", strs[1], "\"") cdRequest(conn, strs[1]) case uiPwd: pwdRequest(conn) case uiQuit: conn.Close( ) os.Exit(0) default: fmt.Println("Unknown command") } }}

func dirRequest(conn net.Conn) { conn.Write([ ]byte(DIR + " "))

var buf [512]byte result := bytes.NewBuffer(nil) for { / / read till we hit a blank line n, _ := conn.Read(buf[0:]) result.Write(buf[0:n]) length := result.Len( ) contents := result.Bytes( ) if string(contents[length-4:]) == "\r\n\r\n" { fmt.Println(string(contents[0 : length-4])) return } }}

func cdRequest(conn net.Conn, dir string) { conn.Write([ ]byte(CD + " " + dir)) var response [512]byte n, _ := conn.Read(response[0:]) s := string(response[0:n]) if s != "OK" { fmt.Println("Failed to change dir") }}

func pwdRequest(conn net.Conn) { conn.Write([ ]byte(PWD)) var response [512]byte n, _ := conn.Read(response[0:])

VISITE UMA IGREJA EVANGELICA

Page 98: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

s := string(response[0:n]) fmt.Println("Current dir \"" + s + "\"")}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Estado Aplicações muitas vezes fazem uso de informações de estado para simplificar o que está

acontecendo. Por exemplo

Manter ponteiros de arquivos para o local do arquivo atual Mantendo a posição atual do mouse Manter o valor do cliente atual.

Em um sistema distribuído, tais informações de estado pode ser mantido no cliente, no servidor, ou em ambos.

O ponto importante é que se um processo é manter informações de estado sobre si ou sobre o outro processo. Um processo pode manter informações de estado tanto sobre si mesmo como ele quer, sem causar quaisquer problemas. Se ele precisa para manter as informações sobre o estado de outro processo, então surgem problemas: o processo de "conhecimento real do estado do outro podem tornarse incorrecta.

Isso pode ser causado pela perda de mensagens (em UDP), por falta de atualização, ou por erros s / w.

Um exemplo é a leitura de um arquivo. Em aplicações de processos individuais do código de manipulação de arquivo é executado como parte da aplicação. Ele mantém uma arquivos de concursos públicos e localização em cada um deles. Cada vez que uma leitura ou gravação é feita neste local arquivo é atualizado. No sistema de arquivos do D o servidor de arquivo mantém o controle de arquivos abertos de um cliente, e onde ponteiro de arquivo do cliente é. Se uma mensagem poderia ter usos perdidos (mas DCE TCP) estes poderiam ficar fora de sincronia. Se o cliente deixa de funcionar, o servidor deve, eventualmente, tempo limite em tabelas de arquivos do cliente e removê-los.

Em NFS, o servidor não manter este estado. O cliente faz. Cada acesso a arquivos do cliente que atinge o servidor deve abra o arquivo no local apropriado, como determinado pelo cliente, para executar a ação.

VISITE UMA IGREJA EVANGELICA

Page 99: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Se o servidor mantém informações sobre o cliente, então ele deve ser capaz de se recuperar se o cliente deixa de funcionar. Se a informação não for salvo, em seguida, em cada transação o cliente deve transferir informações suficientes para que o servidor para funcionar.

Se a conexão não é confiável, então manipulação adicional devem estar no local para garantir que os dois não ficam fora de sincronia. O clássico exemplo é de transações bancárias onde as mensagens se perder.

Um servidor de transação pode precisar de ser parte do cliente sistema do servidor.

Aplicação Estado Diagrama de Transição

Um diagrama de transição de estado mantém o controle do estado atual de um aplicativo e as mudanças que movê-lo para novos estados.

Exemplo: transferência de arquivos com login:

Isto também pode ser expresso como uma mesa

Current state Transition Next state

loginlogin failed login

login succeeded file transfer

file transfer dir file transfer

VISITE UMA IGREJA EVANGELICA

Page 100: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

get file transfer

logout login

quit -

Diagramas de transição de estado Cliente

O diagrama de estado cliente deve seguir o diagrama de aplicativo. Tem mais detalhes, porém: ele escreve e depois lê

Current state Write Read Next state

login LOGIN name passwordFAILED login

SUCCEEDED file transfer

file transfer

CD dirSUCCEEDED file transfer

FAILED file transfer

GET filename#lines + contents file transfer

ERROR file transfer

DIR#files + filenames file transfer

ERROR file transfer

quit none quit

logout none login

Diagramas de transição de estado do servidorO diagrama de estado do servidor também deve seguir o diagrama de aplicativo. Ele também tem

mais detalhes: ele lê e escreve

Current state Read Write Next state

login LOGIN name passwordFAILED login

SUCCEEDED file transfer

file transfer

CD dirSUCCEEDED file transfer

FAILED file transfer

GET filename#lines + contents file transfer

ERROR file transfer

DIR#files + filenames file transfer

ERROR file transfer

quit none quit

logout none login

Pseudocódigo Servidor

state = loginwhile true

VISITE UMA IGREJA EVANGELICA

Page 101: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

read line switch (state) case login: get NAME from line get PASSWORD from line if NAME and PASSWORD verified write SUCCEEDED state = file_transfer else write FAILED state = login case file_transfer: if line.startsWith CD get DIR from line if chdir DIR okay write SUCCEEDED state = file_transfer else write FAILED state = file_transfer ...

Nós não damos o código real para esse servidor ou do cliente, uma vez que é bastante simples.

conjuntos de caracteres e codificações de Gestão

Há muitas línguas em uso em todo o mundo, e eles usam muitos diferentes conjuntos de caracteres. Há também muitas maneiras de codificar os conjuntos nos binários formatos de bytes. Este capítulo considera algumas das questões no presente.

Era uma vez, havia EBCDIC e ASCII ... Na verdade, nunca foi tão simples e acaba de se tornar mais complexo ao longo do tempo.

Há luz no horizonte, mas algumas estimativas são de que ele pode ser de 50 anos antes de todos nós vivemos na luz do dia sobre isso!

Os primeiros computadores foram desenvolvidos nos países de língua Inglês de os EUA, Reino Unido e Austrália. Como resultado disto, suposições foram feitas sobre a língua e conjuntos de caracteres em uso. Basicamente, o alfabeto latino foi usado, além de números, caracteres de pontuação e alguns outros. Estes foram então codificados em bytes usando ASCII ou EBCDIC.

Os mecanismos de manipulação de caracteres foram baseados sobre isso: arquivos de texto e I / O consistiu em uma sequência de bytes, com cada byte representando um único personagem. Comparação de string poderia ser feito por correspondência bytes correspondentes; conversões de superior para minúscula pode ser feito através do mapeamento de bytes individuais, e assim por diante.

Há cerca de 6.000 línguas vivas no mundo (3.000 deles em Papua Nova Guiné!). Alguns idiomas utilizam o "Inglês", mas a maioria não. As línguas românicas, como o francês tem adornos em vários personagens, de modo que você pode escrever “J'ai arrêté", com duas vogais acentuadas de forma diferente. Da mesma forma, as línguas germânicas têm personagens extras, como 'ß'. Mesmo Reino Unido

Inglês tem caracteres não no conjunto padrão ASCII: o símbolo de libra "E." e, recentemente, o euro '€'

Mas o mundo não está restreito às variações no alfabeto latino. Tailândia tem seu próprio alfabeto, com palavras parecido com isto:

"ภาษา ไทย". Há muitos outros alfabetos e Japão ainda tem dois, Hiragana e Katagana.

Há também as línguas hierographic como o chinês, onde você pode escrever "百度 一下, 你 就 知道".Seria bom do ponto de vista técnico, se o mundo acabou de usar ASCII. No entanto, a tendência é no

sentido oposto, com mais e mais usuários exigentes que software usar a linguagem que eles estão familiarizados. Se você criar um aplicativo que pode ser executado em diferentes países, então os usuários vão exigir que ele usa sua própria língua. Em um sistema de distribuição, diferentes componentes da sistema pode ser usado por usuários que esperam diferentes idiomas e caracteres.

Internacionalização (i18n) é a forma como você escreve suas aplicações para que eles possam lidar com a variedade de línguas e culturas.

VISITE UMA IGREJA EVANGELICA

Page 102: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Localização (l10n) é o processo de personalizar seu aplicativo internacionalizado a um grupo cultural particular.

i18n e l10n são grandes temas em si mesmos. Por exemplo, eles cobrem questões como as cores: brancas, enquanto meios "pureza" no Oeste culturas, significa "morte" para os chineses e "alegria" para os egípcios. Neste capítulo, basta olhar para as questões de manipulação de caracteres.

Definições

É importante ter cuidado com o que exatamente parte de um sistema de tratamento de texto que você está falando. Aqui está um conjunto de definições que provaram ser úteis.

A personagem é uma "unidade de informação que corresponde aproximadamente a um grafema (símbolo escrito) de uma linguagem natural, como um carta, numeral, ou sinal de pontuação "(Wikipedia). Um personagem é" o menor componente da linguagem escrita que tem uma semântica valor "(Unicode). Isto inclui letras como 'a' e 'A' (ou cartas em qualquer outra língua), dígitos, como '2 ', caracteres de pontuação como ',' e vários símbolos, como o símbolo de libra Inglês moeda 'R'.

A personagem é uma espécie de abstração de qualquer símbolo real: o caráter 'a' é qualquer escrito 'a' como um círculo platônico é para qualquer círculo real. O conceito de personagem também inclui caracteres de controle, que não correspondem aos símbolos da linguagem natural, mas para outros pedaços de informações usadas para processar textos da língua.

A personagem não tem qualquer aspecto particular, apesar de utilizar a aparência para ajudar a reconhecer o personagem. No entanto, até mesmo a aparência pode ter que ser entendida em um contexto: na matemática, se você ver o símbolo π (pi) é o caráter para a relação da circunferência de raio de um círculo, enquanto que, se você estiver lendo texto grego, é a letra do alfabeto XVI: "προσ" é a palavra grega para "com" e não tem nada a ver com 3,14159 ...

Repertório de caracteres / conjunto de caracteres

Um repertório de caracteres é um conjunto de personagens distintos, tais como o alfabeto latino. Sem ordenação especial é assumida. Em Inglês, apesar de dizer que 'a' é no início do alfabeto de 'z', não diria que 'a' é inferior a 'z'. A "lista telefónica" ordenação que coloca "McPhee" antes "Macrea" mostra que "ordem alfabética" não é crítico para os personagens.

Um repertório especifica os nomes dos personagens e muitas vezes uma amostra de como os personagens pode parecer. Por exemplo, a letra 'a' força parecido com 'a', ' um 'ou' um '. Mas não forçá-los a se parecer com isso eles são apenas amostras. O repertório pode fazer distinções, tais como letras maiúsculas e minúsculas, de modo que 'a' e 'A' são diferentes. Mas pode considerá-los como o mesmo, apenas com a amostra diferente aparências. (Assim como algumas linguagens de programação tratar superior e inferior como diferente por exemplo, Go . Mas alguns não, por exemplo Basic). Outro lado, um repertório pode conter caracteres diferentes com a mesma aparência da amostra: o repertório para uma grego matemático teria duas personagens diferentes, com aparência π. Isto também é chamado um conjunto de caracteres noncoded.

Código de caracteres

Um código de caracteres é um mapeamento de caracteres para números inteiros. O mapeamento de um conjunto de caracteres também é chamado de conjunto de caracteres código definido. O valor de cada personagem deste mapeamento é muitas vezes chamado de um ponto de código. ASCII é um conjunto de códigos. O codepoint para 'a' é d e para 'A' é 65 (decimal).

O código personagem ainda é uma abstração. Ainda não é o que vamos ver em arquivos de texto, ou em pacotes TCP. No entanto, ele está se aproximando.

Pois fornece o mapeamento de conceitos humanos orientada para os numéricos.

A codificação de caracteres

Para comunicar ou armazenar um personagem que você precisa codificá-lo de alguma forma. Para transmitir uma string, você precisa codificar todos os caracteres a string. Há muitas codificações possíveis para qualquer conjunto de códigos.

Por exemplo, 7bit pontos de código ASCII pode ser codificado como se em bytes de 8 bits (um octeto). Então ASCII 'A' (com codepoint 65) é codificado como o octeto 8 bits 01000001. No entanto, uma codificação diferente seria usar o bit de topo para verificação de paridade por exemplo, com estranho

VISITE UMA IGREJA EVANGELICA

Page 103: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

paridade ASCII "A" seria o octeto 11000001. Alguns protocolos, como XDR da Sun usar 32bit de codificação palavra de comprimento. ASCII 'A' seria codificado como 00000000 00000000 0000000 01000001.

A codificação de caracteres é onde nós funcionam no nível de programação. Nossos programas de lidar com caracteres codificados. É, obviamente, faz diferença se estamos lidando com caracteres de 8 bits, com ou sem a verificação da paridade, ou com caracteres de 32 bits. A codificação se estende a cadeias de caracteres. Uma palavra de comprimento paridade codificação de "ABC" pode ser 10000000 (bit de paridade em alta byte) 0100000011 (C) 01000010 (B) 01000001 (A, em baixo byte). Os comentários sobre a importância de uma codificação aplicam-se igualmente fortemente para strings, em que as regras podem ser diferentes.

Codificação dos Transportes

A codificação de caracteres são suficientes para lidar com caracteres dentro de um único aplicativo. No entanto, quando você começar a enviar mensagens de texto aplicações, então não há a emissão de como os bytes, shorts ou palavras são colocadas no fio. Uma codificação pode ser baseado em entre técnicas de largura de banda de economia de espaço e, portanto, como zip'Ping no texto. Ou ela pode ser reduzida para um formato de 7 bits para permitir uma paridade bit verificação, comobase64 .

Se nós sabemos o caráter e codificação de transporte, então é uma questão de programação para gerenciar caracteres e strings. Se não sei o caráter ou a codificação de transporte, então é uma questão de adivinhação, como o que fazer com qualquer sequência particular. Tem nenhuma convenção para arquivos para sinalizar a codificação de caracteres.

Não é, contudo, uma convenção para a sinalização de codificação em texto transmitido através da internet. É simples: o cabeçalho de um texto mensagem contém informações sobre a codificação. Por exemplo, um cabeçalho HTTP pode conter linhas como

Content-Type: text/html; charset=ISO-8859-4Content-Encoding: gzip

Que diz que o conjunto de caracteres ISO 88594 é (o que corresponde a determinados países da Europa) com o padrão de codificação, mas, em seguida,

gziped. A segunda parte codificação de conteúdo é o que estamos nos referindo a como "codificação de transferência" (IETF RFC 2130).

Mas como você ler essa informação? Não é codificado? Não temos uma situação de galinha e ovo? Bem, não. A convenção é que tal informação é dada em ASCII (para ser preciso, EUA ASCII) para que um programa pode ler os cabeçalhos e, em seguida, ajustar o seu codificação para o resto do documento.

ASCII

ASCII tem o repertório dos caracteres em inglês, mais dígitos, pontuação e alguns caracteres de controle. Os pontos de código para ASCII é dado pela tabela familiarizados

Oct Dec Hex Char Oct Dec Hex Char ------------------------------------------------------------ 000 0 00 NUL '\0' 100 64 40 @ 001 1 01 SOH 101 65 41 A 002 2 02 STX 102 66 42 B 003 3 03 ETX 103 67 43 C 004 4 04 EOT 104 68 44 D 005 5 05 ENQ 105 69 45 E 006 6 06 ACK 106 70 46 F 007 7 07 BEL '\a' 107 71 47 G 010 8 08 BS '\b' 110 72 48 H 011 9 09 HT '\t' 111 73 49 I 012 10 0A LF '\n' 112 74 4A J 013 11 0B VT '\v' 113 75 4B K 014 12 0C FF '\f' 114 76 4C L 015 13 0D CR '\r' 115 77 4D M 016 14 0E SO 116 78 4E N

VISITE UMA IGREJA EVANGELICA

Page 104: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

017 15 0F SI 117 79 4F O 020 16 10 DLE 120 80 50 P 021 17 11 DC1 121 81 51 Q 022 18 12 DC2 122 82 52 R 023 19 13 DC3 123 83 53 S 024 20 14 DC4 124 84 54 T 025 21 15 NAK 125 85 55 U 026 22 16 SYN 126 86 56 V 027 23 17 ETB 127 87 57 W 030 24 18 CAN 130 88 58 X 031 25 19 EM 131 89 59 Y 032 26 1A SUB 132 90 5A Z 033 27 1B ESC 133 91 5B [ 034 28 1C FS 134 92 5C \ '\\' 035 29 1D GS 135 93 5D ] 036 30 1E RS 136 94 5E ^ 037 31 1F US 137 95 5F _ 040 32 20 SPACE 140 96 60 ` 041 33 21 ! 141 97 61 a 042 34 22 " 142 98 62 b 043 35 23 # 143 99 63 c 044 36 24 $ 144 100 64 d 045 37 25 % 145 101 65 e 046 38 26 & 146 102 66 f 047 39 27 ' 147 103 67 g 050 40 28 ( 150 104 68 h 051 41 29 ) 151 105 69 i 052 42 2A * 152 106 6A j 053 43 2B + 153 107 6B k 054 44 2C , 154 108 6C l 055 45 2D - 155 109 6D m 056 46 2E . 156 110 6E n 057 47 2F / 157 111 6F o 060 48 30 0 160 112 70 p 061 49 31 1 161 113 71 q 062 50 32 2 162 114 72 r 063 51 33 3 163 115 73 s 064 52 34 4 164 116 74 t 065 53 35 5 165 117 75 u 066 54 36 6 166 118 76 v 067 55 37 7 167 119 77 w 070 56 38 8 170 120 78 x 071 57 39 9 171 121 79 y 072 58 3A : 172 122 7A z 073 59 3B ; 173 123 7B { 074 60 3C < 174 124 7C | 075 61 3D = 175 125 7D } 076 62 3E > 176 126 7E ~ 077 63 3F ? 177 127 7F DEL

A codificação mais comum para ASCII utiliza os pontos de código de bytes de 7 bits, de modo que a codificação de "A", por exemplo, é de 65.

Este conjunto é realmente ASCII EUA. Devido aos desejos europeus para caracteres acentuados, alguns caracteres de pontuação são omitidos para formar um conjunto mínimo, ISO 646, enquanto há "variantes nacionais" com personagens europeias adequadas. A página

http:/ /www.cs.tut.fi/jkorpela/chars.html por Jukka Korpela tem mais informações para os interessados. Não vamos precisar deles variantes embora.

ISO 8859

VISITE UMA IGREJA EVANGELICA

Page 105: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Octetos são agora o tamanho padrão de bytes. Isso permite que 128 pontos de código extra para extensões para ASCII. Um número de código diferente conjuntos para capturar os repertórios de vários subconjuntos de línguas europeias são a série ISO 8859. ISO 88591 também é conhecido como Latin1 e abrange muitas línguas na Europa Ocidental, enquanto outros nesta série cobrir o resto da Europa e até hebraico, Árabe e tailandês. Por exemplo, ISO 88595 inclui os caracteres cirílicos de países como a Rússia, enquanto a ISO 88598 inclui do alfabeto hebraico.

A codificação padrão para esses conjuntos de caracteres é usar seu ponto de código como um valor de 8 bits. Por exemplo, o caractere 'A' na ISO

88591 tem o ponto de código 193 e é codificado como 193. Todos da série ISO 8859 tem o fundo de 128 valores idênticos para ASCII, de modo que os caracteres ASCII são os mesmos em todos esses jogos.

As especificações HTML usado para recomendar o conjunto de caracteres ISO 88591. HTML 3.2 foi o último a fazê-lo, e depois disso HTML 4.0 recomenda Unicode. Em 2010, o Google fez uma estimativa de que as páginas que vê, cerca de 20% ainda estavam em ISO 8859 formato, enquanto 20% ainda estavam em ASCII ("Unicode se aproximando de 50% da web" http:/ /googleblog.blogspot.com/2010/01/unicode-nearing 50deweb.html).

Unicode

Nem ASCII nem ISO 8859 cobrir as línguas com base em hieróglifos. Chinês é estimado para ter aproximadamente 20.000 separado caracteres, com cerca de 5.000 em uso comum. Estes precisam de mais do que um byte, e tipicamente dois bytes foi usado. Não tem sido muitos destes conjuntos de caracteres de dois bytes: Big5, EUCTW, GB2312 e GBK / GBX para o chinês, JIS X 0208 para o japonês, e assim por diante. Estas codificações geralmente não são mutuamente compatível.

Unicode é um conjunto de caracteres padrão abrangente destinada a cobrir todos os principais conjuntos de caracteres em uso. Inclui europeus, asiáticos, Indiano e muitos mais. Cabe agora a versão 5.2 e tem mais de 107.000 caracteres. O número de pontos de código já ultrapassa 65.536, o que é. mais do que 2 ^ 16. Isto tem implicações para codificação de caracteres.

Os primeiros 256 pontos de código correspondem a ISO 88591, com ASCII EUA como o primeiro 128. Assim, há uma compatibilidade retroativa com estes grandes conjuntos de caracteres, como os pontos de código para ISO 88591 e ASCII são exatamente os mesmos em Unicode. O mesmo não é verdade para outros conjuntos de caracteres: por exemplo, enquanto a maioria dos caracteres Big5 também estão em Unicode, os pontos de código não são os mesmos. O http:/ /moztw.org/docs/big5/table/unicode1.1-obsolete.txt página contém um exemplo de uma (grande) mapeamento de tabela a partir de Big5

Unicode.Para representar caracteres Unicode em um sistema de computador, uma codificação deve ser

utilizado. A UCS codificação é uma codificação de dois bytes usando os valores de ponto de código de caracteres Unicode. No entanto, uma vez que existem agora muitos caracteres em Unicode para encaixá-los todos em 2 bytes, essa codificação é obsoleto e não é mais usado. Em vez disso, são os seguintes:

UTF32 é uma codificação de 4 bytes, mas não é comumente usado, e HTML 5 adverte explicitamente contra a usá-lo

UTF16 codifica os caracteres mais comuns em 2 bytes com mais 2 bytes para o "estouro", com ASCII e ISO 88591 com os valores usuais

UTF8 usa entre 1 e 4 bytes por caractere, com ASCII com os valores usuais (mas não ISO 88591) UTF7 é usado algumas vezes, mas não é comum

UTF8: Go e runes

UTF8 é a codificação mais comumente usado. Google estima que 50% das páginas que ele vê são codificados em UTF8. O Conjunto ASCII tem os mesmos valores de codificação em UTF8, assim que um leitor de UTF8 pode ler o texto que consiste de apenas caracteres ASCII, bem como texto a partir do conjunto Unicode completo.

Go usa caracteres UTF8 codificado em suas strings. Cada personagem é do tipo. Este é um alias para rune int32 como um caractere Unicode pode ser 1, 2 ou 4 bytes na codificação UTF8. Em termos de personagens, uma string é uma array de runes.

Uma string é também uma array de bytes, mas você tem que ter cuidado: somente para o subconjunto ASCII é um byte igual a um personagem. Todos os outros caracteres ocupam dois, três ou quatro bytes. Isto significa que o comprimento de uma cadeia de caracteres (runes) não é geralmente o

VISITE UMA IGREJA EVANGELICA

Page 106: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

mesmo que o comprimento do seu array de bytes. Eles só são iguais quando a string é composto por apenas caracteres ASCII.

O fragmento de programa a seguir ilustra isso. Se dermos uma string UTF8 e testar sua extensão, você obter o comprimento do subjacente array de bytes. Mas se você lançar a string para um array de runes então você obtém uma array de pontos de código Unicode que é geralmente [ ] Rune o número de caracteres:

str := "百度一下,你就知道 "println("String length", len([ ]rune(str)))println("Byte length", len(str))

Impressões

String length 9Byte length 27

UTF8 cliente e servidor

Possivelmente surpreendentemente, você não precisa fazer nada especial para lidar com UTF8 texto em que o cliente ou o servidor. O tipo de dados subjacente para uma string UTF8 em Go é um array de bytes, e como vimos logo acima, Go cuida codificando a string em 1, 2, 3 ou 4 bytes como necessário. O comprimento da string é o comprimento da array de bytes, assim você escrever qualquer string UTF8 por escrever a array de bytes.

Da mesma forma para ler uma string, você acabou de ler em um array de bytes e, em seguida, converter a array em uma string usando string ([ ] byte). Se Go não pode decodificar corretamente bytes em caracteres Unicode, então ele dá a substituição de caracteres Unicode \ uFFFD. O comprimento do resultando array de bytes é o comprimento da parte legal da string.

Assim, os clientes e servidores dadas nos capítulos anteriores funcionam perfeitamente bem com UTF8 texto codificado.

Cliente e servidor ASCII

Os caracteres ASCII tem a mesma codificação em ASCII e UTF8. UTF8 manuseio personagem tão comum funciona bem para ASCII caracteres. Nenhum tratamento especial precisa ser feito.

6,7 UTF16 and Go

UTF16 lida com arrays de 16 bits inteiros sem sinal curtas. O pacoteUTF16 foi concebido para gerir essas arrays. Para converter um string Go normal, que é uma string UTF8, em UTF16, primeiro você extrair os pontos de código coagindoo em um e depois usar [ ] Rune utf16.Encodepara produzir uma array do tipo uint16.

Da mesma forma, para decodificar uma série de curtos não assinados UTF16 valores em uma string Go, você usa utf16.Decodeconvertêlo em pontos de código como Tipo e então a uma string. O seguinte fragmento de código ilustra esta [ ] Rune. Gerenciando conjuntos de caracteres e codificações

str := "百度一下,你就知道 "runes := utf16.Encode([ ]rune(str))ints := utf16.Decode(runes)str = string(ints)

Essas conversões de tipo devem ser aplicados por clientes ou servidores, conforme apropriado, para ler e escrever inteiros curtos de 16 bits, como mostra abaixo.

Littleendian e bigendian

Infelizmente, há um pouco de demônio à espreita por trás UTF16. É basicamente uma codificação de caracteres em inteiros curtos de 16 bits. O grande questão é: para cada resumo, como está escrito como dois bytes? A de cima primeiro, ou no topo um segundo? De qualquer forma é bom, contanto como o

VISITE UMA IGREJA EVANGELICA

Page 107: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

receptor usa a mesma convenção como o remetente.Unicode abordou está com um carácter especial conhecido como o BOM (marca de ordem de bytes).

Este é um não impressão de largura zero personagem, para que você nunca vê-lo em texto. Mas a sua 0xfffe valor é escolhido de modo que você pode dizer a bytecorder:

Em um sistema bigendian é FF FE Em um sistema de littleendian é FE FF

Texto, por vezes, colocar o BOM como o primeiro caractere no texto. O leitor pode então examinar esses dois bytes para determinar o endianness foi usada.

Cliente e servidor UTF16

Usando a convenção BOM, podemos escrever um servidor que acrescenta um BOM e escreve uma string em UTF16 como

/* UTF16 Server */package main

import ( "fmt" "net" "os" "unicode/utf16")

const BOM = '\ufffe'

func main( ) {

service := "0.0.0.0:1210" tcpAddr, err := net.ResolveTCPAddr("tcp", service) checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { conn, err := listener.Accept( ) if err != nil { continue }

str := "j'ai arrêté" shorts := utf16.Encode([ ]rune(str)) writeShorts(conn, shorts)

conn.Close( ) / / we're finished }}

_, err := conn.Write(bytes[0:]) if err != nil { return }

for _, v := range shorts { bytes[0] = byte(v >> 8) bytes[1] = byte(v & 255)

VISITE UMA IGREJA EVANGELICA

Page 108: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

_, err = conn.Write(bytes[0:]) if err != nil { return } }}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Extraia e examine o cliente servidor

/* UTF16 Client*/package main

import ( "fmt" "net" "os" "unicode/utf16")

const BOM = '\ufffe'

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } service := os.Args[1]

conn, err := net.Dial("tcp", service) checkError(err)

shorts := readShorts(conn) ints := utf16.Decode(shorts) str := string(ints)

fmt.Println(str)

os.Exit(0)}

func readShorts(conn net.Conn) [ ]uint16 { var buf [512]byte

/ / read everything into the buffer n, err := conn.Read(buf[0:2]) for true { m, err := conn.Read(buf[n:]) if m == 0 || err != nil { break } n += m }

VISITE UMA IGREJA EVANGELICA

Page 109: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

checkError(err) var shorts [ ]uint16 shorts = make([ ]uint16, n/2)

if buf[0] == 0xff && buf[1] == 0xfe { / / big endian for i := 2; i < n; i += 2 { shorts[i/2] = uint16(buf[i])<<8 + uint16(buf[i+1]) } } else if buf[1] == 0xff && buf[0] == 0xfe { / / little endian for i := 2; i < n; i += 2 { shorts[i/2] = uint16(buf[i+1])<<8 + uint16(buf[i]) } } else { / / unknown byte order fmt.Println("Unknown order") } return shorts

}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

ISO 8859 e Go

A série ISO 8859 são conjuntos de caracteres de 8 bits para diferentes partes da Europa e algumas outras áreas. Todos eles têm o conjunto ASCII comum na parte de baixo, mas diferem na sua parte superior. Segundo o Google, códigos ISO 8859 representam cerca de 20% das páginas da web que vê.

O primeiro código, ISO 88591 ou Latin1, tem os primeiros 256 caracteres em comum com Unicode. O valor codificado do Latin1 caracteres é a mesma em UTF16 e na codificação padrão ISO 88591. Mas isso realmente não ajuda muito, como UTF16 é um 16bit codificação e ISO 88591 é uma codificação de 8 bits. UTF8 é uma codificação de 8 bits, mas ele usa o top bit para sinalizar bytes extras, portanto, apenas o Subconjunto ASCII sobrepõe para UTF8 e ISO 88591. Então UTF8 não ajuda muito.

Mas a série ISO 8859 não tem quaisquer problemas complexos. Para cada personagem em cada conjunto corresponde um carácter único Unicode.

Por exemplo, na ISO 88592, o caractere "letra maiúscula latina I com ogonek" tem ISO 88592 0xc7 ponto de código (em hexadecimal) e correspondente ponto de U 012 E. código Unicode Transformando dois sentidos, entre um conjunto de ISO 8859 e Unicode correspondente caracteres é essencialmente apenas uma pesquisa de tabela.

A tabela a partir de ISO 8859 pontos de código para pontos de código Unicode poderia ser feito como um array de 256 inteiros. Mas muitos destes vontade tem o mesmo valor que o índice. Então, é só usar um mapa dos diferentes, e aqueles que não o mapa tirar o valor do índice.

Para ISO 88592 uma parte do mapa é

var unicodeToISOMap = map[int] uint8 { 0x12e: 0xc7, 0x10c: 0xc8, 0x118: 0xca, / / plus more}

e uma função para converter UTF8 strings para uma array de ISO 88592 bytes é

VISITE UMA IGREJA EVANGELICA

Page 110: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

/* Turn a UTF-8 string into an ISO 8859 encoded byte array*/ func unicodeStrToISO(str string) [ ]byte { / / get the unicode code points codePoints := [ ]int(str) / / create a byte array of the same length bytes := make([ ]byte, len(codePoints))

for n, v := range(codePoints) { / / see if the point is in the exception map iso, ok := unicodeToISOMap[v] if !ok { / / just use the value iso = uint8(v) } bytes[n] = iso } return bytes}

De uma maneira similar você CACN mudar uma série de ISO 88592 bytes em uma string UTF8:

var isoToUnicodeMap = map[uint8] int { 0xc7: 0x12e, 0xc8: 0x10c, 0xca: 0x118, / / and more}

func isoBytesToUnicode(bytes [ ]byte) string { codePoints := make([ ]int, len(bytes)) for n, v := range(bytes) { unicode, ok :=isoToUnicodeMap[v] if !ok { unicode = int(v) } codePoints[n] = unicode } return string(codePoints)}

Essas funções podem ser usadas para ler e escrever UTF8 strings como ISO 88592 bytes. Ao alterar a tabela de mapeamento, você pode cobrir os outros códigos ISO 8859. Latin1 ou ISO 88591, é um caso especial o mapa exceção é vazio como os pontos de código para Latin1 são os mesmos em Unicode. Você também pode usar a mesma técnica para outros conjuntos de caracteres com base em um mapeamento de tabela, como O Windows 1252

Outros conjuntos de caracteres e Go

Há muito, muito muitos conjuntos de caracteres codificações. Segundo o Google, estes geralmente só tem um pequeno uso, que esperamos diminuir ainda mais no tempo. Mas se o seu software quer capturar todos os mercados, então você pode precisar para lidar com eles.

Nos casos mais simples, uma tabela de consulta será suficiente. Mas isso nem sempre funciona. O ISO de codificação de caracteres 2022 minimizado conjunto de caracteres tamanhos usando uma máquina de estado finito para trocar as páginas de código de entrada e saída. Este foi emprestado por alguns dos japoneses codificações, e torna as coisas muito complexas.

VISITE UMA IGREJA EVANGELICA

Page 111: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Go não neste momento dar qualquer apoio linguagem ou pacote para esses outros conjuntos de caracteres. Então, você quer evitar a sua utilização, não falar com aplicações que fazem uso deles, ou escrever um monte de seu próprio código!

Segurança

Embora a internet foi originalmente concebido como um sistema para suportar atacks por agentes hostis, desenvolveu-se em uma cooperativa ambiente de entidades relativamente confiáveis. Infelizmente, esses dias estão muito longe. Spam, ataques de negação de serviço, as tentativas de phishing e assim por diante são indicativos de que qualquer pessoa que utilize a internet o faz por sua conta e risco.

As candidaturas devem ser construídos para funcionar corretamente em situações hostis. "Corretamente" já não significa apenas ficar os aspectos funcionais do programa correto, mas também significa garantir a privacidade e integridade dos dados transferidos, o acesso apenas a usuários legítimos e outros questões.

Isto, obviamente, faz com que seus programas muito mais complexa. Há difíceis e sutis problemas de computação envolvidos na realização aplicações seguras. As tentativas de fazê-lo sozinho (como inventar suas próprias bibliotecas de criptografia) são normalmente fadada ao fracasso.

Em vez disso, você precisa fazer uso de bibliotecas projetados por profissionais de segurança

arquitetura de segurança ISO

O modelo de sete camadas ISO OSI (interligação de sistemas abertos), de sistemas distribuídos é bem conhecida e é repetida nesta figura:

O que é menos conhecido é que a ISO construída toda uma série de documentos sobre esta arquitetura. Para os nossos propósitos aqui, o mais importante é o modelo de Arquitetura de Segurança ISO, ISO 74982.

Funções e níveis

As principais funções exigidas de um sistema de segurança são

Autenticação prova de identidade A integridade dos dados os dados não são adulterados Sigilo dados não está exposta a outros Cartório / assinatura O controle de acesso Garantia / disponibilidade

Estes são necessários para os seguintes níveis de pilha OSI:

Entidade autenticação ponto (3, 4, 7) Autenticação da origem de dados (3, 4, 7)

VISITE UMA IGREJA EVANGELICA

Page 112: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Serviço de controle de acesso (3, 4, 7) Confidencialidade de conexão (1, 2, 3, 4, 6, 7) Confidencialidade conexão (1, 2, 3, 4, 6, 7) Confidencialidade campo Seletiva (6, 7) Fluxo de tráfego confidencialidade (1, 3, 7) A integridade da conexão com a recuperação (4, 7) A integridade da conexão sem recuperação (4, 7) Campo seletiva integridade de conexão (7) Campo seletiva integridade sem conexão (7) Não repúdio na origem (7) Não repúdio de recepção (7) Peer entidade autenticação Criptografia Assinatura digital Troca de autenticação Autenticação da origem de dados Criptografia Assinatura digital Serviço de controle de acessoListas de controle de acessoSenhasCapacidades listasRótulos Confidencialidade de conexãoecryptionControle de roteamento Confidelity sem conexãoCriptografiaControle de roteamento Confidelity campo seletivaCriptografia Fluxo de tráfego confidelityCriptografiaPreenchimento tráfegoControle de roteamento A integridade da conexão com recuperaçãoCriptografiaA integridade dos dados A integridade da conexão sem recuperaçãoCriptografiaA integridade dos dados Campo seletivo a integridade da conexãoCriptografiaA integridade dos dados Integridade sem conexãoCriptografiaAssinatura digitalA integridade dos dados Campo seletiva integridade sem conexãoCriptografiaAssinatura digitalA integridade dos dados Não repúdio na origemAssinatura digitalA integridade dos dadosNotarial Não repúdio de recepçãoAssinatura digital

VISITE UMA IGREJA EVANGELICA

Page 113: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

A integridade dos dadosNotarial

A integridade dos dados

Garantir a integridade dos dados, o fornecimento de um meio de testar se os dados não foi adulterado. Geralmente isto é feito através da formação de um simples número de bytes dos dados. Este processo é chamado de hashing e o número resultante é chamado de Hash ou valor de hash.

Um algoritmo de hash ingênuo é apenas a soma de todos os bytes de dados. No entanto, isso ainda permite que quase toda a quantidade de mudar o dados ao redor e ainda preserva os valores de hash. Por exemplo, um invasor pode simplesmente trocar dois bytes. Isso preserva o hash valor, mas pode acabar com você por causa de alguém 65.536 dólares americanos em vez de $ 256.

Algoritmos de hash usado para fins de segurança tem que ser "forte", de modo que é muito difícil para um atacante para encontrar um diferente sequência de bytes com o mesmo valor hash. Isso torna difícil para modificar os dados para fins do atacante. Segurança pesquisadores estão constantemente testando algoritmos de hash para ver se eles podem quebrá-los ou seja, encontrar uma maneira simples de chegar com byte sequências para corresponder a um valor de hash. Eles criaram uma série de criptografia algoritmos de hash que se acredita ser forte.

Go tem suporte para vários algoritmos de hash, incluindo MD4, MD5, RIPEMD160, SHA1, sha224, SHA256, SHA384 e SHA512. Todos eles seguem o mesmo padrão, tanto quanto o programador Go está em causa: a função (Ou similar) no apropriado Novo pacote Hash retorna um Hash objeto do pacote.

Uma Hash tem um io.Writer, E você escreve os dados a serem hash a este escritor. Você pode consultar o número de bytes no valor de hash por Tamanho e Soma o valor de hash.

Um caso típico é MD5 hash. Este utiliza o md5 pacote. O valor de hash é um array de bytes 16. Isso normalmente é impresso em ASCII formar como quatro números hexadecimais, cada um composto por 4 bytes. Um programa simples é * MD5Hash

/* MD5Hash */

package main

import ( "crypto/md5" "fmt")

func main( ) { hash := md5.New( ) bytes := [ ]byte("hello\n") hash.Write(bytes) hashValue := hash.Sum(nil) hashSize := hash.Size( ) for n := 0; n < hashSize; n += 4 { var val uint32 val = uint32(hashValue[n])<<24 + uint32(hashValue[n+1])<<16 + uint32(hashValue[n+2])<<8 + uint32(hashValue[n+3]) fmt.Printf("%x ", val) } fmt.Println( )}

que imprime "b1946ac9 2492d234 7c6235b4 d2611184"

Uma variação deste é o HMAC (introduzidosHash Message Authentication Code), que adiciona uma chave para o algoritmo de hash. Há pouca alterar na utilização deste. Para usar o MD5 hash junto com uma chave, substituir a chamada para por new

VISITE UMA IGREJA EVANGELICA

Page 114: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

func NewMD5(key [ ]byte) hash.Hash

criptografia de chave simétrica

Existem dois principais mecanismos utilizados para a criptografia de dados. A primeira usa uma única chave que é o mesmo para a criptografia e descriptografia. Essa chave precisa ser conhecido tanto para a criptografia e descriptografia dos agentes. Como esta chave é transmitido entre os agentes não é discutido.

Tal como acontece com hash, existem muitos algoritmos de criptografia. Muitos estão agora conhecido por ter fraquezas, e em algoritmos gerais tornar-se mais fraco com o tempo, os computadores ficam mais rápidos. Go tem suporte para vários algoritmos de chave simétrica, como Blowfish e DES.

Os algoritmos são blocos de algoritmos. Ou seja, eles trabalham em blocos de dados. Se os dados não está alinhado com o tamanho do bloco, então você vai tem que preenchê-lo com espaços em branco extras no estreitol.

Cada algoritmo é representado por um no pacote adequado, e leva o simétricoCifra objeto. Isto é criado por NewCipherChave como parâmetro.Depois de ter uma cifra, você pode usá-lo para criptografar e descriptografar blocos de dados. Os

blocos têm de ser blocos de 8 bits para Blowfish. Um programa para ilustrar este é

/* Blowfish */

package main

import ( "bytes" "code.google.com/p/go.crypto/blowfish" "fmt")

func main( ) { key := [ ]byte("my key") cipher, err := blowfish.NewCipher(key) if err != nil { fmt.Println(err.Error( )) } src := [ ]byte("hello\n\n\n") var enc [512]byte

cipher.Encrypt(enc[0:], src)

var decrypt [8]byte cipher.Decrypt(decrypt[0:], enc[0:]) result := bytes.NewBuffer(nil) result.Write(decrypt[0:8]) fmt.Println(string(result.Bytes( )))

Blowfish não é na distribuição Vai 1. Em vez disso, está no site http:/ /code.google.com/p/. Você tem que instalá-lo através do comando "Go buscar" em um diretório onde você tem fonte que precisa usá-lo.

Criptografia de chave pública

Criptografia de chave pública e descriptografia requer duas chaves: uma para criptografar e um segundo para descriptografar. A chave de criptografia é geralmente tornado público, de alguma forma, de modo que qualquer um pode criptografar mensagens para você. A chave de decodificação deve permanecer confidencial, caso contra seria capaz de descodificar essas mensagens! Sistemas de chave pública e assimétrico, com chaves diferentes para diferentes usos.

Existem muitos sistemas de criptografia de chave pública apoiadas pela Go. A um típico é o esquema

VISITE UMA IGREJA EVANGELICA

Page 115: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

RSA.Um programa de geração de RSA chaves públicas e privadas é

/* GenRSAKeys */

package main

import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/gob" "encoding/pem" "fmt" "os")

func main( ) { reader := rand.Reader bitSize := 512 key, err := rsa.GenerateKey(reader, bitSize) checkError(err)

fmt.Println("Private key primes", key.Primes[0].String( ), key.Primes[1].String( )) fmt.Println("Private key exponent", key.D.String( ))

publicKey := key.PublicKey fmt.Println("Public key modulus", publicKey.N.String( )) fmt.Println("Public key exponent", publicKey.E)

saveGobKey("private.key", key) saveGobKey("public.key", publicKey)

savePEMKey("private.pem", key)}

func saveGobKey(fileName string, key interface{ }) { outFile, err := os.Create(fileName) checkError(err) encoder := gob.NewEncoder(outFile) err = encoder.Encode(key) checkError(err) outFile.Close( )}

func savePEMKey(fileName string, key *rsa.PrivateKey) {

outFile, err := os.Create(fileName) checkError(err)

var privateKey = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}

pem.Encode(outFile, privateKey)

outFile.Close( )}

func checkError(err error) { if err != nil {

VISITE UMA IGREJA EVANGELICA

Page 116: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

O programa também guarda os certificados usando serialização gob. Eles podem ser lidos de volta por este programa:

/* LoadRSAKeys */

package main

import ( "crypto/rsa" "encoding/gob" "fmt" "os")

func main( ) { var key rsa.PrivateKey loadKey("private.key", &key)

fmt.Println("Private key primes", key.Primes[0].String( ), key.Primes[1].String( )) fmt.Println("Private key exponent", key.D.String( ))

var publicKey rsa.PublicKey loadKey("public.key", &publicKey)

fmt.Println("Public key modulus", publicKey.N.String( )) fmt.Println("Public key exponent", publicKey.E)}

func loadKey(fileName string, key interface{ }) { inFile, err := os.Open(fileName) checkError(err) decoder := gob.NewDecoder(inFile) err = decoder.Decode(key) checkError(err) inFile.Close( )}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

certificados X.509

A Public Key Infrastructure (PKI) é um framework para uma coleção de chaves públicas, juntamente com informações adicionais, como proprietário nome e localização, e as ligações entre eles, dando algum tipo de mecanismo de aprovação.

O principal PKI em uso hoje é baseada em certificados X.509. Por exemplo, navegadores usam para verificar a identidade de web locais.

Um exemplo de programa para gerar um certificado X.509 autoassinado para o meu site e armazená-

VISITE UMA IGREJA EVANGELICA

Page 117: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

lo em um Cer

/* GenX509Cert */

package main

import ( "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/gob" "encoding/pem" "fmt" "math/big" "os" "time")

func main( ) { random := rand.Reader

var key rsa.PrivateKey loadKey("private.key", &key)

now := time.Now( ) then := now.Add(60 * 60 * 24 * 365 * 1000 * 1000 * 1000) / / one year template := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "jan.newmarch.name", Organization: [ ]string{"Jan Newmarch"}, }, / / NotBefore: time.Unix(now, 0).UTC( ), / / NotAfter: time.Unix(now+60*60*24*365, 0).UTC( ), NotBefore: now, NotAfter: then,

SubjectKeyId: [ ]byte{1, 2, 3, 4}, KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigi-talSignature,

BasicConstraintsValid: true, IsCA: true, DNSNames: [ ]string{"jan.newmarch.name"," "localhost"}, derBytes, err := x509.CreateCertificate(random, &template, &template, &key.PublicKey, &key) checkError(err)

certCerFile, err := os.Create("jan.newmarch.name.cer") checkError(err) certCerFile.Write(derBytes) certCerFile.Close( )

certPEMFile, err := os.Create("jan.newmarch.name.pem") checkError(err) pem.Encode(certPEMFile, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) certPEMFile.Close( )

VISITE UMA IGREJA EVANGELICA

Page 118: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

keyPEMFile, err := os.Create("private.pem") checkError(err) pem.Encode(keyPEMFile, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(&key)}) keyPEMFile.Close( )}

func loadKey(fileName string, key interface{ }) { inFile, err := os.Open(fileName) checkError(err) decoder := gob.NewDecoder(inFile) err = decoder.Decode(key) checkError(err) inFile.Close( )}func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Agora Vamos

/* GenX509Cert */

package main

import ( "crypto/x509" "fmt" "os")

func main( ) { certCerFile, err := os.Open("jan.newmarch.name.cer") checkError(err) derBytes := make([ ]byte, 1000) / / bigger than the file count, err := certCerFile.Read(derBytes) checkError(err) certCerFile.Close( )

/ / trim the bytes to actual length in callcert, err := x509.ParseCertificate(derBytes[0:count]) checkError(err)

fmt.Printf("Name %s\n", cert.Subject.CommonName) fmt.Printf("Not before %s\n", cert.NotBefore.String( )) fmt.Printf("Not after %s\n", cert.NotAfter.String( ))

}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

VISITE UMA IGREJA EVANGELICA

Page 119: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

TLS

Esquemas de codificação / decodificação são de uso limitado, se você tem que fazer todo o trabalho pesado mesmo. O mecanismo mais popular a internet para dar suporte para passar mensagem criptografada é atualmente TLS (Transport Layer Security), que antigamente era SSL (Secure Sockets Layer).

Em TLS, um cliente e um servidor negociar identidade usando certificados X.509. Um isso for concluído, uma chave secreta é inventado entre eles, e todos codificação / decodificação é feito usando essa chave. A negociação é relativamente lento, mas uma vez que completar uma chave mais rápido privado mecanismo é utilizado.

Um servidor e

/* TLSEchoServer */package main

import ( "crypto/rand" "crypto/tls" "fmt" "net" "os" "time")

func main( ) {

cert, err := tls.LoadX509KeyPair("jan.newmarch.name.pem", "private.pem") checkError(err) config := tls.Config{Certificates: [ ]tls.Certificate{cert}}

now := time.Now( ) config.Time = func( ) time.Time { return now } config.Rand = rand.Reader

service := "0.0.0.0:1200"

listener, err := tls.Listen("tcp", service, &config) checkError(err) fmt.Println("Listening") for { conn, err := listener.Accept( ) if err != nil { fmt.Println(err.Error( )) continue } fmt.Println("Accepted") go handleClient(conn) }}

func handleClient(conn net.Conn) { defer conn.Close( )

var buf [512]byte for { fmt.Println("Trying to read") n, err := conn.Read(buf[0:])

VISITE UMA IGREJA EVANGELICA

Page 120: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

if err != nil { fmt.Println(err) } _, err2 := conn.Write(buf[0:n]) if err2 != nil { return } }}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

O servidor trabalha com o seguinte cliente:

/* TLSEchoClient */package main

import ( "fmt" "os" "crypto/tls")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } service := os.Args[1]

conn, err := tls.Dial("tcp", service, nil) checkError(err)

for n := 0; n < 10; n++ { fmt.Println("Writing...") conn.Write([ ]byte("Hello " + string(n+48))) var buf [512]byte n, err := conn.Read(buf[0:]) checkError(err)

fmt.Println(string(buf[0:n])) } os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

HTTP

VISITE UMA IGREJA EVANGELICA

Page 121: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

A World Wide Web é um grande sistema distribuído, com milhões de usuários. Um site pode tornar-se um host da Web, executando um servidor HTTP servidor. Enquanto os clientes da Web normalmente são os usuários com um navegador, existem muitos outros "agentes de usuário", como aranhas, web clientes de aplicativos e assim por diante.

A Web é construído em cima do HTTP (HyperTexto Transport Protocol), que está no topo das camadas TCP. HTTP tem sido através de três versões disponíveis publicamente, mas o mais recente versão 1.1 é agora o mais comumente usado.

Neste capítulo vamos dar uma visão geral do HTTP, seguido pelo Go APIs para gerenciar conexões HTTP.

Vista de HTTP

URLs e recursos

URLs especificar a localização de um recurso. Um recurso é muitas vezes um arquivo estático, como um documento HTML, uma imagem ou um arquivo de som. Cada vez mais, pode ser um objeto gerado dinamicamente, talvez, com base nas informações armazenadas num banco de dados.

Mas Quando um agente de usuário solicita um recurso, o que é retornado não é o recurso em si, mas alguns representação desse recurso. Para exemplo, se o recurso é um arquivo estático, então o que é enviado para o agente de usuário é uma cópia do arquivo.

Múltiplas URLs podem apontar para o mesmo recurso, e um servidor HTTP retornará representações adequadas do recurso para cada URL. Por exemplo, uma empresa pode tornar a informação produto disponível tanto interna como externamente, utilizando diferentes URLs para o mesmo produto. A representação interna do produto pode incluir informações como agentes de contato internas para a produto, enquanto que a representação externa pode incluir a localização de lojas que vendem o produto.

Este ponto de vista de recursos significa que o protocolo HTTP pode ser bastante simples e direto, enquanto um servidor HTTP pode ser arbitrariamente complexa. HTTP tem que entregar os pedidos de agentes de usuário para os servidores e retornar um fluxo de bytes, enquanto um servidor pode ter para fazer qualquer quantidade de processamento do pedido.

Características HTTP

HTTP é um, sem conexão, protocolo confiável apátrida. Na forma mais simples, a cada pedido de um agente do usuário é tratado de forma confiável e em seguida, a conexão é quebrada. Cada pedido envolve uma conexão TCP em separado, por isso, se muitas reources são necessários (como imagens incorporado em uma página HTML), então muitas conexões TCP tem que ser configurado e derrubado em um curto espaço de tempo.

Terá muitas optimizações em HTTP, que aumentam a complexidade da estrutura simples, a fim de criar uma forma mais eficiente e fiável protocolo.

Versões

Existem 3 versões do HTTPVersão 0.9 totalmente obsoletoVersão 1.0 quase obsoletoVersão 1.1 atual

Cada versão deve entender as solicitações e respostas de versões anteriores.

HTTP 0.9

Formato da solicitação

Request = Simple-RequestSimple-Request = "GET" SP Request-URI CRLF

VISITE UMA IGREJA EVANGELICA

Page 122: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Formato de resposta

Response = Simple-ResponseSimple-Response = [Entity-Body]

HTTP 1.0

Esta versão acrescentado muito mais informações para as solicitações e respostas. Ao invés de "crescer" o formato 0.9, foi apenas deixado juntamente com a nova versão.

Formato da solicitação

O formato de pedidos do cliente para o servidor é

Request = Simple-Request | Full-Request

Simple-Request = "GET" SP Request-URI CRLF

Full-Request = Request-Line *(General-Header | Request-Header | Entity-Header) CRLF [Entity-Body]

Asimples pedido é uma solicitação HTTP/0.9 e deve ser respondida por uma simples resposta.A Linha Request tem formatoRequest-Line = Method SP Request-URI SP HTTP-Version CRLF

Onde

Method = "GET" | "HEAD" | POST |extension-method

Ex:

GET http:/ /jan.newmarch.name/index.html HTTP/1.0

Formato de resposta

A resposta é da forma

Response = Simple-Response | Full-Response

Simple-Response = [Entity-Body]

Full-Response = Status-Line *(General-Header | Response-Header | Entity-Header) CRLF [Entity-Body]

A Linha de Status fornece informações sobre o destino do pedido:

Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

VISITE UMA IGREJA EVANGELICA

Page 123: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Ex:

HTTP/1.0 200 OK

Os códigos são

Status-Code = "200" ; OK | "201" ; Created | "202" ; Accepted | "204" ; No Content | "301" ; Moved permanently | "302" ; Moved temporarily | "304" ; Not modified | "400" ; Bad request | "401" ; Unauthorised | "403" ; Forbidden | "404" ; Not found | "500" ; Internal server error | "501" ; Not implemented | "502" ; Bad gateway | "503" | Service unavailable | extension-code

A entidade cabeçalho contém informações úteis sobre o EntityBody seguir

Entity-Header = Allow | Content-Encoding | Content-Length | Content-Type | Expeires | Last-Modified | extension-header

Por exemplo

HTTP/1.1 200 OKDate: Fri, 29 Aug 2003 00:59:56 GMTServer: Apache/2.0.40 (Unix)Accept-Ranges: bytesContent-Length: 1595Connection: closeContent-Type: text/html; charset=ISO-8859-1

HTTP 1.1

HTTP 1.1 correções de muitos problemas com HTTP 1.0, mas é mais complexo por causa disso. Esta versão é feita através da extensão ou reestreitomento do opções disponíveis para HTTP 1.0. Ex:

Existem mais comandos como TRACE e CONNECT Você deve usar URLs absolutos, especialmente para conectar por proxies por exemplo

GET http:/ /www.w3.org/index.html HTTP/1.1

Há mais atributos como IfModifiedSince, também para uso por proxies

As mudanças incluem

Identificação hostname (permite hosts virtuais)

VISITE UMA IGREJA EVANGELICA

Page 124: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Negociação de conteúdo (vários idiomas) Conexões persistentes (reduz despesas gerais TCP isto é muito confuso) Transferências fragmentada Intervalos de bytes (solicitação de partes de documentos) Suporte a proxy

O protocolo 0.9 tomou uma página. O protocolo foi descrito em 1.0 a cerca de 20 páginas. 1.1 tem 120 páginas.

Simples usuário agentes

Os agentes do usuário como navegadores fazer pedidos e obter respostas. O tipo de resposta é

type Response struct { Status string / / e.g. "200 OK" StatusCode int / / e.g. 200 Proto string / / e.g. "HTTP/1.0" ProtoMajor int / / e.g. 1 ProtoMinor int / / e.g. 0

RequestMethod string / / e.g. "HEAD", "CONNECT", "GET", etc.

Header map[string]string

Body io.ReadCloser

ContentLength int64

TransferEncoding [ ]string

Close bool

Trailer map[string]string}

Examinaremos esta estrutura de dados por meio de exemplos. O pedido mais simples é de um agente de usuário é "Cabeça", que pede informações sobre um recurso e seu servidor HTTP. A função

func Head(url string) (r *Response, err os.Error)

Pode ser usada para fazer esta consulta.

O estado da resposta está no campo de resposta Status, Enquanto que o campo Header é um mapa dos campos do cabeçalho do HTTP resposta. Um programa para fazer esse pedido e apresentar os resultados é

/* Head*/package mainimport (

"fmt" "net/http" "os")

func main( ) { if len(os.Args) != 2 {

VISITE UMA IGREJA EVANGELICA

Page 125: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } url := os.Args[1]

response, err := http.Head(url) if err != nil { fmt.Println(err.Error( )) os.Exit(2) }

fmt.Println(response.Status) for k, v := range response.Header { fmt.Println(k+":", v) }

os.Exit(0)}

Quando executado em um recurso como em ele imprime algo como Cabeça http:/ /www.golang.com/

200 OKContent-Type: text/html; charset=utf-8Date: Tue, 14 Sep 2010 05:34:29 GMTCache-Control: public, max-age=3600Expeires: Tue, 14 Sep 2010 06:34:29 GMTServer: Google Frontend

Normalmente, estamos deseja recuperar um recurso ao invés de apenas obter informações sobre isso. O pedido de "GET" vai fazer isso, e isso pode ser feito usando func Get (string url) (r * Resposta, string estreitolURL, err os.Error)

func Get(url string) (r *Response, estreitolURL string, err os.Error)

O conteúdo da resposta está no campo de resposta Body que é do tipo io.ReadCloser . Nós podemos imprimir o conteúdo para a tela com o seguinte programa

/* Get */

package main

import ( "fmt" "net/http" "net/http/httputil" "os" "strings")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } url := os.Args[1]

response, err := http.Get(url) if err != nil { fmt.Println(err.Error( ))

VISITE UMA IGREJA EVANGELICA

Page 126: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

os.Exit(2) }

if response.Status != "200 OK" { fmt.Println(response.Status) os.Exit(2) }

b, _ := httputil.DumpResponse(response, false) fmt.Print(string(b))

contentTypes := response.Header["Content-Type"] if !acceptableCharset(contentTypes) { fmt.Println("Cannot handle", contentTypes) os.Exit(4) }

var buf [512]byte reader := response.Body for { n, err := reader.Read(buf[0:]) if err != nil { os.Exit(0) } fmt.Print(string(buf[0:n])) } os.Exit(0)}

func acceptableCharset(contentTypes [ ]string) bool { / / each type is like [text/html; charset=UTF-8] / / we want the UTF-8 only for _, cType := range contentTypes { if strings.Index(cType, "UTF-8") != -1 { return true } } return false}

Note que existem questões importantes do conjunto de caracteres do tipo discutido no capítulo anterior. O servidor Irá entregar o conteúdo usando alguma codificação de caracteres e, possivelmente, alguns codificação de transferência. Normalmente, isso é uma questão de negociação entre o usuário agente e servidor, mas o simples comando que estamos usando não inclui o componente de agente de usuário da negociação. Assim Obter o servidor pode enviar o que codificação de caracteres que desejar.

Configurando solicitações

HTTP Vá também fornece uma interface de nível mais baixo para os agentes do usuário para se comunicar com servidores HTTP. Como você poderia esperar, não só dar-lhe mais controle sobre as solicitações do cliente, mas exige que você gaste mais esforço na construção das solicitações. No entanto, só há um ligeiro aumento.

O tipo de dados usado para construir pedidos é o tipo Request. Este é um tipo complexo, e é dada na documentação Go como

type Request struct { Method string / / GET, POST, PUT, etc. RawURL string / / The raw URL given in the request. URL *URL / / Parsed URL.

VISITE UMA IGREJA EVANGELICA

Page 127: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Proto string / / "HTTP/1.0" ProtoMajor int / / 1 ProtoMinor int / / 0

/ / A header maps request lines to theGo values. / / If the header says / / / / accept-encoding: gzip, deflate / / Accept-Language: en-us / / Connection: keep-alive / / / / then / / / / Header = map[string]string{ / / "Accept-Encoding": "gzip, deflate", / / "Accept-Language": "en-us", / / "Connection": "keep-alive", / / } / / / / HTTP defines that header names are case-insensitive. / / The request parser implements this by canonicalizing the / / name, making the first character and any characters / / following a hyphen uppercase and the rest lowercase. Header map[string]string

/ / The message body. Body io.ReadCloser

/ / ContentLength records the length of the associated content. / / The value -1 indicates that the length is unknown. / / Values >= 0 indicate that the given number of bytes may be read from Body. ContentLength int64

/ / TransferEncoding lists the transfer encodings from outermost to innermost. / / An empty list denotes the "identity" encoding. TransferEncoding [ ]string

/ / Whether to close the connection after replying to this request. Close bool

/ / The host on which the URL is sought. / / Per RFC 2616, this is either the value of the Host: header / / or the host name given in the URL itself. Host string / / The referring URL, if sent in the request. / / / / Referer is misspelled as in the request itself, / / a mistake from the earliest days of HTTP. / / This value can also be fetched from the Header map / / as Header["Referer"]; the benefit of making it / / available as a structure field is that the compiler / / can diagnose programs that use the alternate / / (correct English) spelling req.Referrer but cannot / / diagnose programs that use Header["Referrer"]. Referer string

/ / The User-Agent: header string, if sent in the request. UserAgent string

/ / The parsed form. Only available after ParseForm is called.

VISITE UMA IGREJA EVANGELICA

Page 128: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Form map[string][ ]string

/ / Trailer maps trailer keys to values. Like for Header, if the / / response has multiple trailer lines with the same key, they will be / / concatenated, delimited by commas. Trailer map[string]string}

Existe uma grande quantidade de informação que pode ser armazenada em um pedido. Você não precisa preencher todos os campos, apenas aqueles de interesse. O mais sim maneira de criar um pedido com os valores padrão é de, por exemplo,

request, err := http.NewRequest("GET", url.String( ), nil)

Uma vez que o pedido tenha sido criado, você pode modificar os campos. Por exemplo, para especificar que você só quiser receber UTF8, adicionar um Campo "Accept-Charset", a um pedido de

request.Header.Add("Accept-Charset", "UTF-8;q=1, ISO-8859-1;q=0")

(Note que o padrão definido ISO88591 sempre recebe um valor de um a menos que explicitamente mencionado na lista.).

Um cliente de criação de um pedido charset é simples pelo acima. Mas há uma certa confusão sobre o que acontece com o retorno do servidor valor de um charset. O recurso devolvido should deve ter um ContentType que Irá especificar o tipo de mídia do conteúdo, como. Se adequado, o tipo de mídia deve declarar o charset, como text / html; charset = UTF8. Se não houver nenhuma charset text / html especificação, em seguida, de acordo com a especificação HTTP ele deve ser tratado como padrão ISO88591 charset. Mas o HTML 4 especificação afirma que uma vez que muitos servidores não se conformam com isso, então você não pode fazer suposições.

Se há uma codificação especificada no servidor, Em seguida, assumir que é correto se não houver nenhum especificado, uma vez que 50% das páginas ContentType estão em UTF8 e 20% estão em ASCII, então é seguro assumir UTF8. Apenas 30% das páginas pode ser errado.

O objeto Cliente

Para enviar um pedido a um servidor e obter uma resposta, o objeto de conveniência Clienteé a maneira mais fácil. Este objeto pode lidar com múltiplas pedidos e vai cuidar de questões como se o servidor mantém a conexão TCP vivo, e assim por diante.

Isto é ilustrado no seguinte programa

/* ClientGet */

package main

import ( "fmt" "net/http" "net/url" "os" "strings")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "http:/ /host:port/page") os.Exit(1)

VISITE UMA IGREJA EVANGELICA

Page 129: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

} url, err := url.Parse(os.Args[1]) checkError(err)

client := &http.Client{ }

request, err := http.NewRequest("GET", url.String( ), nil) / / only accept UTF-8 request.Header.Add("Accept-Charset", "UTF-8;q=1, ISO-8859-1;q=0") checkError(err)

response, err := client.Do(request) if response.Status != "200 OK" { fmt.Println(response.Status) os.Exit(2) }

chSet := getCharset(response) fmt.Printf("got charset %s\n", chSet) if chSet != "UTF-8" { fmt.Println("Cannot handle", chSet) os.Exit(4) }

var buf [512]byte reader := response.Body fmt.Println("got body") for { n, err := reader.Read(buf[0:]) if err != nil { os.Exit(0) } fmt.Print(string(buf[0:n])) }

os.Exit(0)}

func getCharset(response *http.Response) string { contentType := response.Header.Get("Content-Type") if contentType == "" { / / guess return "UTF-8" } idx := strings.Index(contentType, "charset:") if idx == -1 { / / guess return "UTF-8" } return strings.Trim(contentType[idx:], " ")}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

manuseio Proxy

VISITE UMA IGREJA EVANGELICA

Page 130: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Procuração simples

HTTP 1.1 definidos como HTTP deve funcionar através de um proxy. Um pedido de "GET" deve ser feito para um proxy. No entanto, o URL solicitado deve ser o URL completo do destino. Além disso, o cabeçalho HTTP deve conter um campo "Host", previsto para o proxy. Como desde que o proxy é configurado para passar esses pedidos através, então isso é tudo o que precisa ser feito.

Go considera que isso seja parte da camada de transporte HTTP. Para gerenciar este tem uma classe Transport. Este contém um campo que pode Transporte ser definido para um função que retorna uma URL para um proxy. Se temos uma URL como uma sequência para o proxy, o objeto de transporte adequado é criado e dado a um objeto cliente

proxyURL, err := url.Parse(proxyString)transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)}client := &http.Client{Transport: transport}

O cliente pode então continuar como antes.O programa a seguir ilustra isso:

/* ProxyGet */

package main

import ( "fmt" "io" "net/http" "net/http/httputil" "net/url" "os")

func main( ) { if len(os.Args) != 3 { fmt.Println("Usage: ", os.Args[0], "http:/ /proxy-host:port http:/ /host:port/page") os.Exit(1) } proxyString := os.Args[1] proxyURL, err := url.Parse(proxyString) checkError(err) rawURL := os.Args[2] url, err := url.Parse(rawURL) checkError(err)

transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)} client := &http.Client{Transport: transport}

request, err := http.NewRequest("GET", url.String( ), nil)

dump, _ := httputil.DumpRequest(request, false) fmt.Println(string(dump))

response, err := client.Do(request)

checkError(err) fmt.Println("Read ok")

if response.Status != "200 OK" {

VISITE UMA IGREJA EVANGELICA

Page 131: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

fmt.Println(response.Status) os.Exit(2) } fmt.Println("Reponse ok")

var buf [512]byte reader := response.Body for { n, err := reader.Read(buf[0:]) if err != nil { os.Exit(0) } fmt.Print(string(buf[0:n])) }

os.Exit(0)}

func checkError(err error) { if err != nil { if err == io.EOF { return } fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Se você tiver um proxy, digamos, XYZ.com na porta 8080, testar isso

go run ProxyGet.go http:/ /XYZ.com:8080/ http:/ /www.google.com

Se você não tem um substituto adequado para testar isso, faça o download e instalar o proxy Squid para o seu próprio computador.

O programa acima usado um proxy conhecida passado como um argumento para o programa. Há muitas maneiras em que proxies podem ser dado a conhecer às aplicações. A maioria dos navegadores tem um menu de configuração na qual você pode digitar informações de proxy: tal informação é não está disponível para um aplicativo Go. Alguns aplicativos podem obter informações sobre o proxy de um arquivo em algum lugar na sua autoproxy.pac rede: Go não (ainda) não sabe como analisar esses arquivos de Java Script e por isso não pode usá-los. Sistemas Linux usando o Gnome tem um sistema de configuração chamado gconf em que as informações de proxy podem ser armazenados: Go não pode acessar isto. Mas ele pode encontrar informações de proxy se estiver definido nas variáveis de ambiente do sistema operacional, como

HTTP_PROXY ou http_proxy utilizando a função

func ProxyFromEnvironment(req *Request) (*url.URL, error)

Se seus programas estão sendo executados em um ambiente como esse você pode usar esta função em vez de ter que saber explicitamente o proxy parâmetros.

A autenticação do proxy

Alguns proxies exigirá autenticação, por um nome de usuário e senha, a fim de passar pedidos. Um esquema comum é "básico autenticação ", em que o nome de usuário e senha são concatenadas em uma string" user: password "e depois BASE64 codificado.

Este é então dada para o proxy pelo cabeçalho HTTP request "ProxyAuthentication " com a flag que é a autenticação básica O programa a seguir ilustrastes isso, adicionando o cabeçalho ProxyAuthentication para o programa de proxy anterior:

VISITE UMA IGREJA EVANGELICA

Page 132: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

/* ProxyAuthGet*/package main

import ( "encoding/base64" "fmt" "io" "net/http" "net/http/httputil" "net/url" "os")

const auth = "jannewmarch:mypassword"

func main( ) { if len(os.Args) != 3 { fmt.Println("Usage: ", os.Args[0], "http:/ /proxy-host:port http:/ /host:port/page") os.Exit(1) } proxy := os.Args[1] proxyURL, err := url.Parse(proxy) checkError(err) rawURL := os.Args[2] url, err := url.Parse(rawURL) checkError(err)

/ / encode the auth basic := "Basic " + base64.StdEncoding.EncodeToString([ ]byte(auth))

transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)} client := &http.Client{Transport: transport} request, err := http.NewRequest("GET", url.String( ), nil)

request.Header.Add("Proxy-Authorization", basic) dump, _ := httputil.DumpRequest(request, false) fmt.Println(string(dump))

/ / send the request response, err := client.Do(request)

checkError(err) fmt.Println("Read ok")

if response.Status != "200 OK" { fmt.Println(response.Status) os.Exit(2) } fmt.Println("Reponse ok")

var buf [512]byte reader := response.Body for { n, err := reader.Read(buf[0:]) if err != nil { os.Exit(0) } fmt.Print(string(buf[0:n])) }

os.Exit(0)

VISITE UMA IGREJA EVANGELICA

Page 133: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

}

func checkError(err error) { if err != nil { if err == io.EOF { return } fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

conexões HTTPS por clientes

Para conexões seguras e criptografadas, HTTP usa TLS, que é descrito no capítulo sobre segurança. O protocolo de HTTP + TLS é chamado HTTPS e usa URLs https:/ / em vez de http:/ / urls.

Os servidores são obrigados a devolver os certificados X.509 válidos antes de um cliente aceitará dados a partir deles. Se o certificado é válido, então Go lida com tudo sob o capô e os clientes dadas anteriormente executar bem com URLs HTTPS.

Muitos sites têm certificados inválidos. Eles podem ter expeirado, podem ser auto assinado em vez de por um certificado reconhecido

Autoridade ou eles podem simplesmente ter erros (tais como ter um nome de servidor incorreto). Navegadores como o Firefox colocar um aviso grande com um "Tiremme daqui!" botão, mas você pode continuar a seu risco o que muitas pessoas fazem.

Go atualmente socorre quando encontra erros de certificado. Há um apoio cauteloso para exercer, mas eu não tenho que trabalhar ainda. Portanto, não há exemplo atual de "exercer, em face da adversidade:)". Talvez mais tarde.

servidores

O outro lado para a construção de um cliente é um servidor Web manipulação de solicitações HTTP. As mais simples e mais antirás os servidores apenas devolvidos cópias de arquivos. No entanto, qualquer URL agora pode desencadear um cálculo arbitrário em servidores atuais.

O servidor de arquivos

Começamos com um servidor de arquivos básico. Go fornece uma multiplexer, Ou seja, um objeto que Irá ler e interpretar solicitações. Ele distribui pedidos para que funcionam em seu próprio segmento. Assim, grande parte do trabalho de ler solicitações HTTP, decodificando-os e manipuladores ramificando para funções adequadas em seu próprio segmento é feito por nós.

Para um servidor de arquivos, Go também dá uma FileServer objeto que sabe como entregar os arquivos do sistema de arquivos local. É preciso um "root" diretório que é o topo de uma árvore de arquivos no sistema local, e um padrão para corresponder URLs contra. O padrão mais simples é "/", que é a parte superior de qualquer URL. Isso Irá corresponder a todos os URLs.

Um servidor HTTP fornecendo arquivos do sistema de arquivos local é quase embaraçosamente trivial dado a esses objetos.

/* File Server */

package main

import ( "fmt" "net/http" "os")

VISITE UMA IGREJA EVANGELICA

Page 134: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

func main( ) { / / deliver files from the directory /var/www / /fileServer := http.FileServer(http.Dir("/var/www")) fileServer := http.FileServer(http.Dir("/home/httpd/html/")

/ / register the handler and deliver requests to it err := http.ListenAndServe(":8000", fileServer) checkError(err) / / That's it!}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

É Este servidor ainda oferece "404 Not Found" mensagens de pedidos de recursos de arquivos que não existem!

Funções de manipulador

Neste último programa, o manipulador foi dado no segundo argumento para ListenAndServe. Qualquer número de manipuladores podem ser registrados primeiro por chamadas Handle para ouhandleFunc, Com as assinaturas

func Handle(pattern string, handler Handler)func HandleFunc(pattern string, handler func(*Conn, *Request))

O segundo argumento para HandleAndServe pode ser nil, em seguida, as chamadas são enviados para todos os manipuladores registrados. Cada manipulador HandleAndServe deve ter um padrão de URL diferente. Por exemplo, o manipulador de arquivo pode ter padrão de URL "/" enquanto um manipulador de função pode ter Padrão de URL "/ cgibin". Um padrão mais específica prevalece sobre um padrão mais geral.

Programas CGI comuns são testcgi (Escrito no shell) ou printenv (Escrito em Perl), que imprime os valores do ambiente variáveis. Um manipulador pode ser escrito para o trabalho de uma forma similar.

/* Print Env */

package main

import ( "fmt" "net/http" "os")

func main( ) { / / file handler for most files fileServer := http.FileServer(http.Dir("/var/www")) http.Handle("/", fileServer)

/ / function handler for /cgi-bin/printenv http.HandleFunc("/cgi-bin/printenv", printEnv)

/ / deliver requests to the handlers

VISITE UMA IGREJA EVANGELICA

Page 135: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

err := http.ListenAndServe(":8000", nil) checkError(err) / / That's it!}

func printEnv(writer http.ResponseWriter, req *http.Request) { env := os.Environ( ) writer.Write([ ]byte("<h1>Environment</h1>\n<pre>")) for _, v := range env { writer.Write([ ]byte(v + "\n")) } writer.Write([ ]byte("</pre>"))}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Nota: para simplificar este programa não entregar HTML bem formado. Está faltando html, cabeça e corpo marcas.

Usando o cgibin diretório neste programa é um pouco atrevido: não chamar um programa externo como scripts CGI fazer. Ele só chama a Go função. Go tem a capacidade de chamar programas externos usando os.ForkExec, Mas ainda não tem suporte para dinamicamente módulos conectáveis como Apache do mod_perl

Ignorando o multiplexer padrão Solicitações HTTP recebidas por um servidor Go geralmente são tratadas por um multiplexer os

examina o caminho no pedido HTTP e chamadas o manipulador de arquivo apropriado, etc Você pode definir seus próprios manipuladores. Estas podem ser registrados com o multiplexer por inadimplência http.HandleFunc chamada o que leva a um padrão e uma função nil. As funções, tais como em seguida ListenAndServe , tomar uma nil função. Isto foi feito no último exemplo.

Se você quiser assumir o papel multiplexer então você pode dar uma função diferente de zero como a função do manipulador. Esta função será então totalmente responsável pela gestão dos pedidos e respostas.

O exemplo a seguir é trivial, mas ilustra a utilização do presente: a função retorna um multiplexador simplesmente "204 Nenhum conteúdo" para todos pedidos:

/* ServerHandler */

package main

import ( "net/http")

func main( ) {

myHandler := http.HandlerFunc(func(rw http.ResponseWriter, request *http.Request) { / / Just return no content - arbitrary headers can be set, arbitrary body rw.WriteHeader(http.StatusNoContent) })

VISITE UMA IGREJA EVANGELICA

Page 136: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

http.ListenAndServe(":8080", myHandler)}

Arbitrariamente comportamento complexo pode ser construído, é claro.

Servidores de baixo nível

Go também fornece uma interface de nível mais baixo para servidores. Novamente, isso significa que, como o programador que tem que fazer mais trabalho. Você primeiro fazer um servidor TCP, e em seguida, enrole uma ServerConn em torno dele. Então você escreve Request's ler Response's.

A resposta mais simples é retornar um "204 Nenhum conteúdo". O seguinte servidor lê os pedidos e despejalos para a saída padrão ao retornar a 204. Manuseio mais complexo poderia ser feito: [um erro ocorreu ao processar esta diretriz orientadora]

Templates

Muitas línguas têm mecanismos para converter cadeias de uma forma para outra. Go tem um mecanismo para converter as cadeias molde com base no conteúdo de um objeto fornecido como um argumento. Enquanto isto é frequentemente usado em reescrever HTML para inserir objeto valores, ele pode ser utilizado em outras situações. Note-se que este material não tem nada explicitamente a ver com a rede, mas pode ser útil para programas de rede.

A maioria das linguagens do lado do servidor tem um mecanismo para a tomada de páginas predominantemente estáticas e inserção de uma gerado dinamicamente componente, tal como uma lista de itens. Exemplos típicos são os scripts em Java Server Pages, scripts PHP e muitos outros. Go tem adotou uma linguagem de script relativamente simples no modelo pacote.

Na hora de escrever um novo pacote de modelo tem sido adotado. Existe muito pouca documentação sobre os pacotes de modelo.

Há uma pequena quantidade na embalagem antiga, que ainda está disponível no. Não há documentação sobre a old / template novo pacote ainda como além da página de referência. O pacote de modelo mudou com r60 (lançado 2011/09/07).

Descreve-se o novo pacote aqui. O pacote é projetado para ter texto como entrada e saída de texto diferente, com base em transformando o texto original usando os valores de um objeto. Ao contrário JSP ou semelhante, que não é restreito a arquivos de HTML, mas é provável que encontrar maior uso lá.

A fonte original é chamado de modelo e será composto por um texto que é transmitida inalterada e comandos embutidos que podem agir e alterar o texto.

Inserção de valores de objeto

Um modelo é aplicado a um objeto Go. Os campos desse objeto Go pode ser inserido no modelo, e você pode "cavar" para o objeto para encontrar subcampos, etc O objeto atual é representado como '.', de modo que para inserir o valor do objeto atual como uma string, você usar{{.}}. O pacote usa o fmt pacote por padrão, para trabalhar a string usada como valores inseridos.

Para inserir o valor de um campo do objeto atual, você usa o nome do campo prefixado por '.'. Por exemplo, se o objeto é do tipo

type Person struct { Name string Age int Emails [ ]string Jobs [ ]*Jobs}

Agora seu name e sua Age

The name is {{.Name}}.The age is {{.Age}}.

Podemos loop sobre os elementos de uma array ou de outra lista, utilizando um comando range. Assim, para acessar o Emails conteúdo do alcance

VISITE UMA IGREJA EVANGELICA

Page 137: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

{{range .Emails}}...{{end}}

Se job é definido por

type Job struct { Employer string Role string}

Ordem o que fazemos e queremos acessar os campos de um Person's Jobs, Nós podemos fazê-lo como acima com um {{Range. Jobs}}. Uma alternativa é mudar o atual objeto para o Jobs campo. Isso é feito usando o construção {{with ...}} ... {{end}}, onde agora {{.}} é o Jobs campo, que é uma array:

{{with .Jobs}} {{range .}} An employer is {{.Employer}} and the role is {{.Role}} {{end}}{{end}}

Você pode usar isso com qualquer campo, e não apenas uma array. <.

A utilização de modelos

Uma vez que temos um modelo, podemos aplicá-la a um objeto para gerar uma nova sequência, usando o objeto para preencher os valores do modelo. Este é um processo de duas etapas que envolve a análise do molde e, em seguida, aplicando-o a um objeto. O resultado é a saída para como em Writer

t := template.New("Person template")t, err := t.Parse(templ)if err == nil { buff := bytes.NewBufferString("") t.Execute(buff, person)}

Um exemplo de programa para aplicar um modelo a um objeto e imprimir para a saída padrão é

/** * PrintPerson */

package main

import ( "fmt" "html/template" "os")

type Person struct { Name string Age int Emails [ ]string Jobs [ ]*Job}

VISITE UMA IGREJA EVANGELICA

Page 138: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

type Job struct { Employer string Role string}

const templ = `The name is {{.Name}}.The age is {{.Age}}.{{range .Emails}} An email is {{.}}{{end}}

{{with .Jobs}} {{range .}} An employer is {{.Employer}} and the role is {{.Role}} {{end}}{{end}}`

func main( ) { job1 := Job{Employer: "Monash", Role: "Honorary"} job2 := Job{Employer: "Box Hill", Role: "Head of HE"}

person := Person{ Name: "jan", Age: 50, Emails: [ ]string{"[email protected]", "[email protected]"}, Jobs: [ ]*Job{&job1, &job2}, }

t := template.New("Person template") t, err := t.Parse(templ) checkError(err)

err = t.Execute(os.Stdout, person) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

A saída deste está

The name is jan.The age is 50.An email is [email protected] email is [email protected] employer is Monashand the role is HonoraryAn employer is Box Hilland the role is Head of HE

Note-se que há uma abundância de espaço em branco como novas linhas neste impressão. Isto é

VISITE UMA IGREJA EVANGELICA

Page 139: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

devido ao espaço em branco que temos em nosso modelo. Se deseja reduzir isso, eliminar novas linhas no modelo como na

{{alcance. Emails}} Um e-mail é {{.}} {{fim}}No exemplo, usamos uma string no programa como modelo. Você também pode carregar modelos a

partir de um arquivo usando a função template.ParseFiles( ). Por alguma razão que eu não entendo (e que não era necessário nas versões anteriores), o nome designado para o modelo deve ser o mesmo que o nome base do primeiro arquivo da lista de arquivos. Isso é um bug?

Pipelines

As transformações acima inserir pedaços de texto em um modelo. Esses pedaços de texto são essencialmente arbitrárias, seja qual for a string valores dos campos são. Se nós queremos que eles aparecem como parte de um documento HTML (ou outra forma especializada), então teremos que sequências de escape específicas de caracteres. Por exemplo, para exibir o texto arbitrário em um documento HTML temos que mudar "<" para "<". Os modelos Vão têm um número de funções embutidas, e um deles é a função. Estas funções de agir de forma semelhante html forma de pipelines Unix, lendo da entrada padrão e escrevendo na saída padrão.

Para tirar o valor do objeto atual '.' e aplicar escapes HTML para isso, você escreve um "pipeline" no modelo

{{. | Html}}

E de forma semelhante para outras funções.

Mike Samuel apontou uma função de conveniência atualmente pacote noexp / template / html. Se todas as entradas em um modelo precisa de ser passado através do pode levar um modelo html função de modelo, então a função Go Escape (t * template.Template) e adicione ohtmlfunc para cada nó no modelo que ainda não tiver um. Isto Irá ser útil para modelos utilizados para Documentos HTML e podem formar um padrão para função similar usa em outros lugares.

Definindo Funções

Os modelos usam a representação de string de um objeto para inserir valores, usando o fmt pacote para converter o objeto para uma string.

Às vezes isso não é o que é necessário. Por exemplo, para evitar spammers Conseguir os endereços de e-mail, é bastante comum ver o símbolo '@' substituída pela palavra "at", como em "janeiro em newmarch.name". Se quiser usar um modelo para exibir os endereços de e-mail nessa forma, então nós temos que construir uma função personalizada para fazer esta transformação.

Cada função de modelo tem um nome que é utilizado nos modelos de si mesmos, e uma função Go associado. Estas estão ligadas através o tipo de interface

type FuncMap map[string]interface{ }

Por exemplo, se queremos que a nossa função de modelo para ser "emailExpand", que está ligada à função Go EmailExpander então adicionar o tipo isso para as funções em um modelo,

t = t.Funcs(template.FuncMap{"emailExpand": EmailExpander})

A assinatura EmailExpander é tipicamente

func EmailExpander(args ...interface{ }) string No uso que está interessado, deve haver apenas um argumento para a função que Irá ser uma string.

Funções em virár no Go biblioteca de modelos têm algum código inicial para lidar com casos de não-conformidade, de modo que basta copiar isso. Em seguida, ele é apenas simples string manipulação para alterar o formato do endereço de e-mail. Um programa/** * PrintEmails */

VISITE UMA IGREJA EVANGELICA

Page 140: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

package main

import ( "fmt" "os" "strings" "text/template")

type Person struct { Name string Emails [ ]string}

const templ = `The name is {{.Name}}.{{range .Emails}} An email is "{{. | emailExpand}}"{{end}}`

func EmailExpander(args ...interface{ }) string { ok := false var s string if len(args) == 1 { s, ok = args[0].(string) } if !ok { s = fmt.Sprint(args...) }

/ / find the @ symbol substrs := strings.Split(s, "@") if len(substrs) != 2 { return s } / / replace the @ by " at " return (substrs[0] + " at " + substrs[1])}

func main( ) { person := Person{ Name: "jan", Emails: [ ]string{"[email protected]", "[email protected]"}, } t := template.New("Person template")

/ / add our function t = t.Funcs(template.FuncMap{"emailExpand": EmailExpander})

t, err := t.Parse(templ)

checkError(err)

err = t.Execute(os.Stdout, person) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1)

VISITE UMA IGREJA EVANGELICA

Page 141: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

}}

A saída está

The name is jan.An email is "jan at newmarch.name"An email is "jan.newmarch at gmail.com"

Variáveis

O pacote de modelo permite que você definir e usar variáveis. Como motivação para isso, considerar como podemos imprimir cada pessoa da endereço de e-mail prefixado pelo seu nome. O tipo que usamos é novamente

Para acessar as strings de e-mail, nós usamos um declaração range como

{{range .Emails}}{{.}}{{end}}

Mas nesse momento, não podemos acessar o campo Name como '.' agora está atravessando os elementos da array e da está fora deste escopo. A solução é guardar o valor do campo de uma variável que pode ser acedida em qualquer lugar o seu âmbito. Variáveis em modelos são prefixados por '$'. Então nós escrevemos

{{$name := .Name}}{{range .Emails}} Name is {{$name}}, email is {{.}}{{end}}

O programa é

/** * PrintNameEmails */

package main

import ( "html/template" "os" "fmt")

type Person struct { Name string Emails [ ]string}

const templ = `{{$name := .Name}}{{range .Emails}} Name is {{$name}}, email is {{.}}{{end}}`

func main( ) { person := Person{

VISITE UMA IGREJA EVANGELICA

Page 142: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Name: "jan", Emails: [ ]string{"[email protected]", "[email protected]"},

} }

t := template.New("Person template") t, err := t.Parse(templ) checkError(err)

err = t.Execute(os.Stdout, person) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Com saída

Name is jan, email is [email protected] is jan, email is [email protected]

declarações condicionais

Continuando com a nosso exemplo Person, supondo que nós só queremos imprimir a lista de e-mails, sem cavar nele. Nós podemos fazer isso com um modelo

Name is janEmails are [[email protected] [email protected]]

Isto Irá imprimir

Nome é janeiroEmails são [[email protected] jan.newmarch @ gmail.com]

Porque é assim que a fmt pacote Irá mostrar uma lista.

Em muitas circunstâncias que podem ficar bem, se é isso que você quer. Vamos considerar um caso em que é quase certo, mas não é bem assim. Lá é um pacote de JSON de serialização de objetos, o que nós verificamos no Capítulo 4. Isso produziria

{"Name": "jan","Emails": ["[email protected]", "[email protected]"]}

O pacote JSON é o que você usaria na prática, mas vamos ver se nós podemos produzir saída JSON usando modelos. Podemos fazer algo semelhante apenas pelos modelos que temos. Isto é quase como um direito serialiser JSON:

{"Name": "{{.Name}}","Emails": {{.Emails}}}

Ela Irá produzir

VISITE UMA IGREJA EVANGELICA

Page 143: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

{"Name": "jan","Emails": [[email protected] [email protected]]}

Que tem dois problemas: os endereços não estão entre aspas, e os elementos da lista deve ser ',' separado.

Como sobre isto: olhar para os elementos da array, colocando-as entre aspas e adicionando vírgulas?

{"Name": {{.Name}}, "Emails": [ {{range .Emails}} "{{.}}", {{end}} ]}

Que Irá produzir

{"Name": "jan","Emails": ["[email protected]", "[email protected]",]}

(Mais algum espaço em branco.).

Mais uma vez, quase correto, mas se você olhar com cuidado, você vai ver uma fuga ',' após o último elemento da lista. De acordo com a sintaxe JSON (Ver http:/ /www.json.org/, esta fuga ',' não é permitido. Implementações podem variar de como eles lidam com isso.

O que queremos é "imprimir cada elemento seguido por um ',' exceto o último." Este é realmente um pouco difícil de fazer, então a melhor maneira é "Imprimir cada elemento precedido por um ',' exceto para o primeiro um. " (Eu tenho essa dica de "brianb" no estouro de pilha.). Isto é mais fácil, porque o primeiro elemento tem índice zero e muitas linguagens de programação, incluindo o modelo de linguagem Go, tratar zero como Booleano falso.

Felizmente, uma variação na {{if pipeline}} T1 {{else}} T0 {{end}} Uma forma da instrução condicional é o array de e-mails. Declaração nos dá isso. Existem duas formas que introduzem variáveis.

{{range $elmt := array}}{{range $index, $elmt := array}}

Precisamos da oleoduto para ser o índice em Então montamos um loop através da array, e se o índice for falsa (0) nós apenas imprimir o elemento, caso contrário imprimi-lo precedido por um ','. O modelo e programa completo é Isto dá a saída JSON correta.

{"Name": "{{.Name}}", "Emails": [ {{range $index, $elmt := .Emails}} {{if $index}} , "{{$elmt}}" {{else}} "{{$elmt}}" {{end}} {{end}} ]}

E o programa comprimento é

/**

VISITE UMA IGREJA EVANGELICA

Page 144: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

* PrintJSONEmails */

package main

import ( "html/template" "os" "fmt")

type Person struct { Name string Emails [ ]string}

const templ = `{"Name": "{{.Name}}", "Emails": [{{range $index, $elmt := .Emails}} {{if $index}} , "{{$elmt}}" {{else}} "{{$elmt}}" {{end}}{{end}} ]}`

func main( ) { person := Person{ Name: "jan", Emails: [ ]string{"[email protected]", "[email protected]"}, }

t := template.New("Person template") t, err := t.Parse(templ) checkError(err)

err = t.Execute(os.Stdout, person) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Antes de deixar este ponto, podemos constatar que o problema da formatação de uma lista com separadores de vírgula pode ser abordado através da definição funções adequadas no Go que são disponibilizados como funções de modelo. Para voltar a usar um ditado bem conhecido ", há mais de uma maneira! fazêlo "O programa a seguir foi enviado a mim por Roger Peppe:

/** * Sequence.go * Copyright Roger Peppe */

VISITE UMA IGREJA EVANGELICA

Page 145: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

package main

import ( "errors" "fmt" "os" "text/template")

func main( ) { t, err := template.New("").Funcs(fmap).Parse(tmpl) if err != nil { fmt.Printf("parse error: %v\n", err) return } err = t.Execute(os.Stdout, [ ]string{"a", "b", "c", "d", "e", "f"}) if err != nil { fmt.Printf("exec error: %v\n", err) }}

type generator struct { ss [ ]string i int f func(s [ ]string, i int) string}

func (seq *generator) Next( ) string { s := seq.f(seq.ss, seq.i) seq.i++ return s}

func sequenceGen(ss [ ]string, i int) string { if i >= len(ss) { return ss[len(ss)-1] } return ss[i]}

func cycleGen(ss [ ]string, i int) string { return ss[i%len(ss)]}

func sequenceFunc(ss ...string) (*generator, error) { if len(ss) == 0 { return nil, errors.New("sequence must have at least one element") } return &generator{ss, 0, sequenceGen}, nil}

func cycleFunc(ss ...string) (*generator, error) { if len(ss) == 0 { return nil, errors.New("cycle must have at least one element") } return &generator{ss, 0, cycleGen}, nil}

VISITE UMA IGREJA EVANGELICA

Page 146: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Conclusão

O pacote de modelo Go é útil para certos tipos de transformações de texto que envolvem a inserção de valores de objetos. Ele não tem o poder de, por exemplo, as expressões regulares, mas é mais rápida e, em muitos casos, será mais fácil de usar do que as expressões regulares

Capítulo 10 Um servidor da Web completa

Este capítulo é, principalmente, uma ilustração longo do capítulo HTTP, a construção de um servidor Web completo em Go. Ele também mostra como usar modelos para usar expressões em arquivos de texto para inserir os valores das variáveis e gerar seções repetidas.

Introdução

Estou aprendendo chinês. Em vez disso, depois de muitos anos de tentativas eu ainda estou tentando aprender chinês. Claro que, em vez de para baixo flambagem e ficando com ela, eu tentei todos os tipos de ajudas técnicas. Tentei DVDs, vídeos, flashcards e assim por diante. Eventualmente, eu percebi que lá não era um bom programa de computador para flashcards chineses, e assim, no interesse da aprendizagem, que eu precisava para construir um.

Eu tinha encontrado um programa em Python para fazer parte da tarefa. Mas, infelizmente, não foi bem escrito e depois de algumas tentativas de transformá-lo de cabeça para baixo e de dentro para fora, cheguei à conclusão de que era melhor para começar do zero. É claro, uma solução Web seria muito melhor do que um autônomo, porque então todas as outras pessoas da minha turma chinês poderia compartilhá-lo, bem como quaisquer outros alunos lá fora. E, claro, o servidor seria escrito em Go.

O servidor está funcionando em flashcards cict.bhtafe.edu.au: 8000. A primeira página é composta por uma lista de conjuntos de cartões, atualmente disponíveis, como você quer um conjunto apresentado (ordem carta aleatória, chinês, Inglês ou aleatório), se deseja exibir um conjunto, adicionar a ele, etc Passei muito tempo construí-lo de alguma forma o meu chinês não progrediu muito enquanto eu estava fazendo isso ... Ele provavelmente não vai ser muito emocionante como um programa, se você não quer aprender chinês, mas vamos entrar na estrutura.

Páginas estáticas

Algumas páginas terá apenas conteúdo estático. Estes podem ser gerenciados por um fileServer . Para simplificar eu coloquei todo o HTML estático páginas e arquivos CSS no htmldiretório e todos os arquivos Java Script na jscript diretório. Estes são, então, entregue pelo Go código

fileServer := http.FileServer("jscript", "/jscript/")http.Handle("/jscript/", fileServer)fileServer = http.FileServer("html", "/html/")http.Handle("/html/", fileServer)

Modelos

A lista de conjuntos de cartões, é em aberto, dependendo do número de arquivos em um diretório. Estes não devem ser codificado em um Página HTML, mas o conteúdo deve ser gerado, conforme necessário. Este é um candidato óbvio para modelos.

<table> {{range .}} <tr> <td> {{.}} </td> </tr>

VISITE UMA IGREJA EVANGELICA

Page 147: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

</table>

A lista de arquivos em um diretório é gerado como uma lista de strings. Estes podem então ser exibidos em uma tabela usando o modelo

O Dicionário chinês

Chinês é uma língua complexa (não são todos:( ). A forma escrita hieroglífica é, isto é "pictogramas" em vez de usar um alfabeto. Mas esta forma escrita tem evoluído ao longo do tempo, e mesmo recentemente dividida em duas formas: "tradicional" chinesa, usado no Taiwan e Hong Kong, e "simplificado" chinês como o usado na China continental. Embora a maior parte dos caracteres são o mesmo, cerca 1.000 são diferentes. Assim, um dicionário chinês, muitas vezes, tem duas formas de escrita do mesmo caráter.

A maioria dos ocidentais como eu não consirá entender esses caracteres. Portanto, há uma forma "Latinized" chamado Pinyin que grava o caracteres em um alfabeto fonético com base no alfabeto latino. Não é bem o alfabeto latino, porque chinês é um tonal língua, e forma Pinyin tem que mostrar os tons (muito parecido acccents em francês e outros idiomas europeus). Assim, um típico dicionário tem que mostrar quatro coisas: a forma tradicional, o formulário simplificado, o Pinyin e inglês.

Por exemplo,

Traditional Simplified Pinyin English

好 好 hǎo good

Mas, novamente, há uma pequena complicação. Há um livre Chinês / Inglês dicionário e, melhor ainda, você pode baixá-lo como UTF8 arquivo, que Go é bem ajustada para controlar. Neste, os caracteres chineses são escritos em Unicode, mas os personagens não são Pinyin:

Embora existam caracteres Unicode para cartas como "ǎ ', muitos dicionários incluindo este usar' a 'do latim e coloque o tom no fim da palavra. Aqui é o terceiro tom, por isso "hão" é escrito como "hao3". Isso torna mais fácil para aqueles que só têm EUA teclados e nenhum editor Unicode ainda comunicar em Pinyin.

Esta incompatibilidade de formatos de dados não é um grande negócio: basta que em algum lugar ao longo da linha, entre o dicionário e texto original da exibir no navegador, uma massagem de dados tem de ser realizada. Go modelos permitem que isso seja feito através da definição de um modelo personalizado, então eu escolhi esse caminho. Alternativas poderia ter sido para fazer isso como o dicionário é lido, ou no Javascript para exibir a estreitol caracteres.

O código para o formatador Pinyin é dada abaixo. Por favor, não se incomode de lê-lo, a menos que você está realmente interessado em saber as regras para formatação Pinyin.

package pinyin

import ( "io" "strings")

func PinyinFormatter(w io.Writer, format string, value ...interface{ }) { line := value[0].(string) words := strings.Fields(line) for n, word := range words { / / convert "u:" to "ü" if present uColon := strings.Index(word, "u:") if uColon != -1 { parts := strings.SplitN(word, "u:", 2) word = parts[0] + "ü" + parts[1] } println(word) / / get last character, will be the tone if present chars := [ ]rune(word)

VISITE UMA IGREJA EVANGELICA

Page 148: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

tone := chars[len(chars)-1] if tone == '5' { words[n] = string(chars[0 : len(chars)-1]) println("lost accent on", words[n]) continue } if tone < '1' || tone > '4' { continue } words[n] = addAccent(word, int(tone)) } line = strings.Join(words, ` `) w.Write([ ]byte(line))}

var ( / / maps 'a1' to '\u0101' etc aAccent = map[int]rune{ '1': '\u0101', '2': '\u00e1', '3': '\u01ce', / / '\u0103', '4': '\u00e0'} eAccent = map[int]rune{ '1': '\u0113', '2': '\u00e9', '3': '\u011b', / / '\u0115', '4': '\u00e8'} iAccent = map[int]rune{ '1': '\u012b', '2': '\u00ed', '3': '\u01d0', / / '\u012d', '4': '\u00ec'} oAccent = map[int]rune{ '1': '\u014d', '2': '\u00f3', '3': '\u01d2', / / '\u014f', '4': '\u00f2'} uAccent = map[int]rune{ '1': '\u016b', '2': '\u00fa', '3': '\u01d4', / / '\u016d', '4': '\u00f9'} üAccent = map[int]rune{ '1': 'ǖ', '2': 'ǘ', '3': 'ǚ', '4': 'ǜ'})

func addAccent(word string, tone int) string { /* * Based on "Where do the tone marks go?" * at http:/ /www.pinyin.info/rules/where.html */

n := strings.Index(word, "a") if n != -1 { aAcc := aAccent[tone] / / replace 'a' with its tone version word = word[0:n] + string(aAcc) + word[(n+1):len(word)-1] } else {

VISITE UMA IGREJA EVANGELICA

Page 149: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

n := strings.Index(word, "e") if n != -1 { eAcc := eAccent[tone] word = word[0:n] + string(eAcc) + word[(n+1):len(word)-1] } else { n = strings.Index(word, "ou") if n != -1 { oAcc := oAccent[tone] word = word[0:n] + string(oAcc) + "u" + word[(n+2):len(word)-1] } else { chars := [ ]rune(word) length := len(chars) / / put tone onthe last vowel L: for n, _ := range chars { m := length - n - 1 switch chars[m] { case 'i': chars[m] = iAccent[tone] break L case 'o': chars[m] = oAccent[tone] break L case 'u': chars[m] = uAccent[tone] break L case 'ü': chars[m] = üAccent[tone] break L default: } } word = string(chars[0 : len(chars)-1]) } } }

}

return word}

Como este é utilizado é ilustrado pela função lookupWord. Isto é chamado em resposta a um pedido de formulário HTML para encontrar o Inglês palavras em um dicionário.

func lookupWord(rw http.ResponseWriter, req *http.Request) { word := req.FormValue("word") words := d.LookupEnglish(word)

pinyinMap := template.FormatterMap {"pinyin": pinyin.PinyinFormatter} t, err := template.ParseFile("html/DictionaryEntry.html", pinyinMap) if err != nil { http.Error(rw, err.String( ), http.StatusInternalServerError) return } t.Execute(rw, words)}

VISITE UMA IGREJA EVANGELICA

Page 150: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

O código HTML é

<html> <body> <table border="1"> <tr> <th>Word</th> <th>Traditional</th> <th>Simplified</th> <th>Pinyin</th> <th>English</th> </tr> {{with .Entries}} {{range .}} {.repeated section Entries} <tr> <td>{{.Word}}</td> <td>{{.Traditional}}</td> <td>{{.Simplified}}</td> <td>{{.Pinyin|pinyin}}</td> <td> <pre> {.repeated section Translations} {@|html} {.end} </pre> </td> </tr> {.end} {{end}} {{end}} </table> </body></html>

O tipo de dicionário

O arquivo de texto que contém o dicionário tem linhas da forma traditional simplified [pinyin] /translation/translation/.../

Por exemplo,好好 [hao3] / bom / bem / adequado / bom / fácil / muito / so / (sufixo que indica conclusão ou

prontidão) /Nós armazenamos cada linha como um na Entrada aqui no Dicionário pacote:

type Entry struct { Traditional string Simplified string Pinyin string Translations [ ]string}

O dicionário em si é apenas uma array dessas entradas:

type Dictionary struct { Entries [ ]*Entry}

VISITE UMA IGREJA EVANGELICA

Page 151: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Construindo o dicionário é bastante fácil. Basta ler cada linha e quebrar a linha em seus vários pedaços usando métodos de string simples. Depois adicione a linha para a slice dicionário.

Olhando para cima entradas neste dicionário é simples: basta pesquisar até encontrar a chave apropriada. Há cerca de 100.000 entradas neste dicionário: a força bruta por uma busca linear é rápido o suficiente. Se fosse necessário, armazenamento e busca mais rápida mecanismos poderiam ser facilmente utilizado.

O dicionário originais cresce por pessoas na Web adicionando em entradas como entenderem. Por conseguinte, não é que bem organizado e contém repetições e múltiplas entradas. Então, olhando para cima qualquer palavra por Pinyin ou Inglês pode retornar várias correspondências. Para servir para isso, cada pesquisa retorna um "mini dicionário", apenas aquelas linhas no dicionário completo que correspondem.

O código é Dicionário

package dictionary

import ( "bufio" / /"fmt" "os" "strings")

type Entry struct { Traditional string Simplified string Pinyin string Translations [ ]string}

func (de Entry) String( ) string { str := de.Traditional + ` ` + de.Simplified + ` ` + de.Pinyin for _, t := range de.Translations { str = str + "\n " + t } return str}

type Dictionary struct { Entries [ ]*Entry}

func (d *Dictionary) String( ) string { str := "" for n := 0; n < len(d.Entries); n++ { de := d.Entries[n] str += de.String( ) + "\n" } return str}

func (d *Dictionary) LookupPinyin(py string) *Dictionary { newD := new(Dictionary) v := make([ ]*Entry, 0, 100) for n := 0; n < len(d.Entries); n++ { de := d.Entries[n] if de.Pinyin == py { v = append(v, de) } }

VISITE UMA IGREJA EVANGELICA

Page 152: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

newD.Entries = v return newD}

func (d *Dictionary) LookupEnglish(eng string) *Dictionary { newD := new(Dictionary) v := make([ ]*Entry, 0, 100) for n := 0; n < len(d.Entries); n++ { de := d.Entries[n] for _, e := range de.Translations { if e == eng { v = append(v, de) } } } newD.Entries = v return newD}

func (d *Dictionary) LookupSimplified(simp string) *Dictionary { newD := new(Dictionary) v := make([ ]*Entry, 0, 100)

for n := 0; n < len(d.Entries); n++ { de := d.Entries[n] if de.Simplified == simp { v = append(v, de) } } newD.Entries = v return newD}

func (d *Dictionary) Load(path string) {

f, err := os.Open(path) r := bufio.NewReader(f) if err != nil { println(err.Error( )) os.Exit(1) }

v := make([ ]*Entry, 0, 100000) numEntries := 0 for { line, err := r.ReadString('\n') if err != nil { break } if line[0] == '#' { continue } / / fmt.Println(line) trad, simp, pinyin, translations := parseDictEntry(line)

de := Entry{ Traditional: trad, Simplified: simp, Pinyin: pinyin, Translations: translations}

VISITE UMA IGREJA EVANGELICA

Page 153: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

v = append(v, &de) numEntries++ } / / fmt.Printf("Num entries %d\n", numEntries) d.Entries = v}

func parseDictEntry(line string) (string, string, string, [ ]string) { / / format is / / trad simp [pinyin] /trans/trans/.../ tradEnd := strings.Index(line, " ") trad := line[0:tradEnd] line = strings.TrimSpace(line[tradEnd:])

simpEnd := strings.Index(line, " ") simp := line[0:simpEnd] line = strings.TrimSpace(line[simpEnd:])

pinyinEnd := strings.Index(line, "]") pinyin := line[1:pinyinEnd] line = strings.TrimSpace(line[pinyinEnd+1:])

translations := strings.Split(line, "/") / / includes empty at start and end, so translations = translations[1 : len(translations)-1]

return trad, simp, pinyin, translations}

Cartões Fash

Cartões Fash é um tipo flash cardis

type FlashCard struct { Simplified string English string Dictionary *dictionary.Dictionary}

No momento nós só armazenar o caráter simplificado e tradução Inglês para esse personagem. Temos também um Dicionário que conterá apenas uma entrada para a entrada, vamos ter escolhido algum lugar.

Um conjunto de cartões de memória flash é definido pelo tipo de

type FlashCards struct { Name string CardOrder string ShowHalf string Cards [ ]*FlashCard}

Onde o CardOrder será "aleatório" ou "sequencial" e o ShowHalf será "RANDOM_HALF" ou "ENGLISH_HALF" ou "CHINESE_HALF" para determinar que a metade de um novo cartão é exibido pela primeira vez.

O código para cartões de memória flash não tem nada de novo nela. Recebemos os dados do

VISITE UMA IGREJA EVANGELICA

Page 154: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

navegador do cliente e usar JSON para criar um objeto da dados de formulário e armazenar o conjunto de flashcards como uma string JSON

A Servidor Completo

O servidor completo é

/* Server */

package main

import ( "fmt" "io/ioutil" "net/http" "os" "regexp" "text/template")

import ( "dictionary" "flashcards" "templatefuncs")

var d *dictionary.Dictionary

func main( ) { if len(os.Args) != 2 { fmt.Fprint(os.Stderr, "Usage: ", os.Args[0], ":port\n") os.Exit(1) } port := os.Args[1] / / dictionaryPath := "/var/www/go/chinese/cedict_ts.u8" dictionaryPath := "cedict_ts.u8" d = new(dictionary.Dictionary) d.Load(dictionaryPath) fmt.Println("Loaded dict", len(d.Entries))

http.HandleFunc("/", listFlashCards) / /fileServer := http.FileServer("/var/www/go/chinese/jscript", "/jscript/") fileServer := http.StripPrefix("/jscript/", http.FileServer(http.Dir("jscript"))) http.Handle("/jscript/", fileServer) / / fileServer = http.FileServer("/var/www/go/chinese/html", "/html/") fileServer = http.StripPrefix("/html/", http.FileServer(http.Dir("html"))) http.Handle("/html/", fileServer)

http.HandleFunc("/wordlook", lookupWord) http.HandleFunc("/flashcards.html", listFlashCards) http.HandleFunc("/flashcardSets", manageFlashCards) http.HandleFunc("/searchWord", searchWord) http.HandleFunc("/addWord", addWord) http.HandleFunc("/newFlashCardSet", newFlashCardSet)

/ / deliver requests to the handlers err := http.ListenAndServe(port, nil) checkError(err) / / That's it!

VISITE UMA IGREJA EVANGELICA

Page 155: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

}

func indexPage(rw http.ResponseWriter, req *http.Request) { index, _ := ioutil.ReadFile("html/index.html") rw.Write([ ]byte(index))}

func lookupWord(rw http.ResponseWriter, req *http.Request) { word := req.FormValue("word") words := d.LookupEnglish(word)

/ /t := template.New("PinyinTemplate") t := template.New("DictionaryEntry.html") t = t.Funcs(template.FuncMap{"pinyin": templatefuncs.PinyinFormatter}) t, err := t.ParseFiles("html/DictionaryEntry.html") if err != nil { http.Error(rw, err.Error( ), http.StatusInternalServerError) return } t.Execute(rw, words)}

type DictPlus struct { *dictionary.Dictionary Word string CardName string}

func searchWord(rw http.ResponseWriter, req *http.Request) { word := req.FormValue("word") searchType := req.FormValue("searchtype") cardName := req.FormValue("cardname")

var words *dictionary.Dictionary var dp [ ]DictPlus if searchType == "english" { words = d.LookupEnglish(word) d1 := DictPlus{Dictionary: words, Word: word, CardName: cardName} dp = make([ ]DictPlus, 1) dp[0] = d1 } else { words = d.LookupPinyin(word) numTrans := 0 for _, entry := range words.Entries { numTrans += len(entry.Translations) } dp = make([ ]DictPlus, numTrans) idx := 0 for _, entry := range words.Entries { for _, trans := range entry.Translations { dict := new(dictionary.Dictionary) dict.Entries = make([ ]*dictionary.Entry, 1) dict.Entries[0] = entry dp[idx] = DictPlus{ Dictionary: dict, Word: trans, CardName: cardName} idx++ } } }

VISITE UMA IGREJA EVANGELICA

Page 156: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

/ /t := template.New("PinyinTemplate") t := template.New("ChooseDictionaryEntry.html") t = t.Funcs(template.FuncMap{"pinyin": templatefuncs.PinyinFormatter}) t, err := t.ParseFiles("html/ChooseDictionaryEntry.html") if err != nil { fmt.Println(err.Error( )) http.Error(rw, err.Error( ), http.StatusInternalServerError) return } t.Execute(rw, dp)}

func newFlashCardSet(rw http.ResponseWriter, req *http.Request) { defer http.Redirect(rw, req, "http:/flashcards.html", 200)

newSet := req.FormValue("NewFlashcard") fmt.Println("New cards", newSet) / / check against nasties: b, err := regexp.Match("[/$~]", [ ]byte(newSet)) if err != nil { return } if b { fmt.Println("No good string") return }

flashcards.NewFlashCardSet(newSet) return}

func addWord(rw http.ResponseWriter, req *http.Request) { url := req.URL fmt.Println("url", url.String( )) fmt.Println("query", url.RawQuery)

word := req.FormValue("word") cardName := req.FormValue("cardname") simplified := req.FormValue("simplified") pinyin := req.FormValue("pinyin") traditional := req.FormValue("traditional") translations := req.FormValue("translations")

fmt.Println("word is ", word, " card is ", cardName, " simplified is ", simplified, " pinyin is ", pinyin, " trad is ", traditional, " trans is ", translations) flashcards.AddFlashEntry(cardName, word, pinyin, simplified, traditional, translations) / / add another card? addFlashCards(rw, cardName)}

func listFlashCards(rw http.ResponseWriter, req *http.Request) {

flashCardsNames := flashcards.ListFlashCardsNames( ) t, err := template.ParseFiles("html/ListFlashcards.html") if err != nil { http.Error(rw, err.Error( ), http.StatusInternalServerError) return }

VISITE UMA IGREJA EVANGELICA

Page 157: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

t.Execute(rw, flashCardsNames)}/* * Called from ListFlashcards.html on form submission */func manageFlashCards(rw http.ResponseWriter, req *http.Request) {

set := req.FormValue("flashcardSets") order := req.FormValue("order") action := req.FormValue("submit") half := req.FormValue("half") fmt.Println("set chosen is", set) fmt.Println("order is", order) fmt.Println("action is", action)

cardname := "flashcardSets/" + set

/ /components := strings.Split(req.URL.Path[1:], "/", -1) / /cardname := components[1] / /action := components[2] fmt.Println("cardname", cardname, "action", action) if action == "Show cards in set" { showFlashCards(rw, cardname, order, half) } else if action == "List words in set" { listWords(rw, cardname) } else if action == "Add cards to set" { addFlashCards(rw, set) }}

func showFlashCards(rw http.ResponseWriter, cardname, order, half string) { fmt.Println("Loading card name", cardname) cards := new(flashcards.FlashCards) / /cards.Load(cardname, d) / /flashcards.SaveJSON(cardname + ".json", cards) flashcards.LoadJSON(cardname, &cards) if order == "Sequential" { cards.CardOrder = "SEQUENTIAL" } else { cards.CardOrder = "RANDOM" } fmt.Println("half is", half) if half == "Random" { cards.ShowHalf = "RANDOM_HALF" } else if half == "English" { cards.ShowHalf = "ENGLISH_HALF" } else { cards.ShowHalf = "CHINESE_HALF" } fmt.Println("loaded cards", len(cards.Cards)) fmt.Println("Card name", cards.Name)

/ /t := template.New("PinyinTemplate") t := template.New("ShowFlashcards.html") t = t.Funcs(template.FuncMap{"pinyin": templatefuncs.PinyinFormatter}) t, err := t.ParseFiles("html/ShowFlashcards.html") if err != nil { fmt.Println(err.Error( )) http.Error(rw, err.Error( ), http.StatusInternalServerError) return }

VISITE UMA IGREJA EVANGELICA

Page 158: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

err = t.Execute(rw, cards) if err != nil { fmt.Println("Execute error " + err.Error( )) http.Error(rw, err.Error( ), http.StatusInternalServerError) return }}

func listWords(rw http.ResponseWriter, cardname string) { fmt.Println("Loading card name", cardname) cards := new(flashcards.FlashCards) / /cards.Load(cardname, d) flashcards.LoadJSON(cardname, cards) fmt.Println("loaded cards", len(cards.Cards)) fmt.Println("Card name", cards.Name)

/ /t := template.New("PinyinTemplate") t := template.New("ListWords.html") if t.Tree == nil || t.Root == nil { fmt.Println("New t is an incomplete or empty template") } t = t.Funcs(template.FuncMap{"pinyin": templatefuncs.PinyinFormatter}) t, err := t.ParseFiles("html/ListWords.html") if t.Tree == nil || t.Root == nil { fmt.Println("Parsed t is an incomplete or empty template") }

if err != nil { fmt.Println("Parse error " + err.Error( )) http.Error(rw, err.Error( ), http.StatusInternalServerError) return } err = t.Execute(rw, cards) if err != nil { fmt.Println("Execute error " + err.Error( )) http.Error(rw, err.Error( ), http.StatusInternalServerError) return } fmt.Println("No error ")}

func addFlashCards(rw http.ResponseWriter, cardname string) { t, err := template.ParseFiles("html/AddWordToSet.html") if err != nil { fmt.Println("Parse error " + err.Error( )) http.Error(rw, err.Error( ), http.StatusInternalServerError) return } cards := flashcards.GetFlashCardsByName(cardname, d) t.Execute(rw, cards) if err != nil { fmt.Println("Execute error " + err.Error( )) http.Error(rw, err.Error( ), http.StatusInternalServerError) return }

}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( ))

VISITE UMA IGREJA EVANGELICA

Page 159: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

os.Exit(1) }}

Outros Bits: Java Script e CSS No pedido, um conjunto de flashcards será carregada no navegador. Um conjunto muito abreviado é

mostrada abaixo. A exibição destes cartões

<html> <head> <title> Flashcards for Common Words </title>

<link type="text/css" rel="stylesheet" href="/html/CardStylesheet.css"> </link>

<script type="text/javascript" language="JavaScript1.2" src="/jscript/jquery.js"> <!-- empty --> </script>

<script type="text/javascript" language="JavaScript1.2" src="/jscript/slideviewer.js"> <!-- empty --> </script>

<script type="text/javascript" language="JavaScript1.2"> cardOrder = RANDOM; showHalfCard = RANDOM_HALF; </script> </head> <body onload="showSlides( );"> <h1> Flashcards for Common Words </h1> <p> <div class="card">

<div class="english"> <div class="vcenter"> hello </div> </div>

<div class="pinyin"> <div class="vcenter"> nǐ hǎo </div>

</div> <div class="traditional"> <div class="vcenter">

VISITE UMA IGREJA EVANGELICA

Page 160: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

你好 </div> </div> <div class="simplified"> <div class="vcenter"> 你好 </div>

</div>

<div class ="translations"> <div class="vcenter"> hello <br /> hi <br /> how are you? <br /> </div>

</div> </div> <div class="card"> <div class="english"> <div class="vcenter"> hello (interj., esp. on telephone) </div> </div>

<div class="pinyin">

<div class="vcenter"> wèi </div> </div> <div class="traditional"> <div class="vcenter"> 喂 </div> </div> <div class="simplified">

<div class="vcenter"> 喂 </div> </div>

<div class ="translations"> <div class="vcenter"> hello (interj., esp. on telephone) <br /> hey <br />

to feed (sb or some animal) <br /> </div> </div> </div> </p>

<p class ="return"> Press <Space> to continue <br/>

VISITE UMA IGREJA EVANGELICA

Page 161: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

<a href="http:/flashcards.html"> Return to Flash Cards list</a> </p> </body></html>

HTML

A Web foi criada originalmente para servir documentos HTML. Agora é utilizado para servir todos os tipos de documentos, bem como dados de tipos dirrent. No entanto, ainda é o colar principal tipo de documento entregue através da Web Go tem mecanismos básicos para análise Documentos HTML.

A Web foi criada originalmente para servir documentos HTML. Agora ele é usado para servir todos os tipos de documentos, bem como dados de tipos dirrent. No entanto, HTML ainda é o principal tipo de documento entregue pela Web HTML tem sido através de um grande número de versões e HTML 5 está atualmente em desenvolvimento. Houve também muitos "Vendedor" versões do HTML, introduzindo marcas que nunca fizeram em padrões.

HTML é simples o suficiente para ser editado manualmente. Consequentemente, muitos documentos HTML são "mal formado", não seguindo a sintaxe a língua. Parsers HTML em geral, não são muito rirárosos, e aceitará muitos documentos "ilegais".

Não havia muito nas versões anteriores do Go sobre a manipulação de documentos HTML basicamente, apenas um tokenizador. A natureza incompleta de o pacote levou à sua remoção para Go 1. Ele pode ainda ser encontrado na expPacote (experimental), se você realmente precisa dele. Sem dúvida alguma forma melhorou estará disponível em uma versão posterior do Go, e, em seguida, ele será adicionado de volta a este livro.

Não há suporte limitado para HTML no pacote XML, discutido no próximo capítulo.

XML

XML é uma linguagem de marcação significativa destina-se principalmente como um meio de serializadas dados estruturas como um documento de texto. Go tem suporte básico para o processamento de documentos XML.

XML é agora uma forma generalizada de representar estruturas de dados complexas serializados em formato de texto. É usada para descrever documentos como DocBook e XHTML. Ela é usada em linguagens de marcação especializadas, tais como MathML e CML (Química Markup Language). Ele é usado para codificar dados como mensagens SOAP para Web Services e Web Service pode ser especificado utilizando WSDL (Web Services Description Language).

No nível mais simples, XML permite que você deestreito suas próprias marcas para uso em documentos de texto. As tags podem ser aninhadas e podem ser intercalados com o texto. Cada tag também pode conter atributos com valores. Por exemplo,

<person> <name> <family> Newmarch </family> <personal> Jan </personal> </name> <email type="personal"> [email protected] </email> <email type="work"> [email protected] </email></person>

A estrutura de qualquer documento XML pode ser descrito de uma série de maneiras:

VISITE UMA IGREJA EVANGELICA

Page 162: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

A DTD definição do tipo de documento é bom para descrever a estruturaEsquema XML são bons para descrever os tipos de dados usados por um documento XMLRELAXAR NG é proposto como uma alternativa

Não há discussão sobre o valor relativo de cada modo de definir a estrutura de um documento XML. Não vamos comprar em que, como Go não suport qualquer deles. Go não é possível verificar a validade de qualquer documento em um esquema, mas apenas para boa formação.

Quatro tópicos são discutidos neste capítulo: analisar um fluxo de XML, triagem e unmarshalling dados entrar em XML e XHTML.

Análise de XML

Go tem um parser XML que é criado usando. Isso leva um io.Readercomo parâmetro e retorna um ponteiro para NewParser Analisador. O principal método deste tipo é Símbolo que retorna o próximo token no fluxo de entrada. O token é um dos tipos, StartElement, EndElement, CharData, Comment, ProcInst ou Directive.

Os tipos são

StartElement

O tipo StartElement é uma estrutura com dois tipos de campos:

type StartElement struct { Name Name Attr [ ]Attr}

type Name struct { Space, Local string}

type Attr struct { Name Name Value string}

EndElement

Esta é também uma estrutura

type EndElement struct { Name Name}

CharData Este tipo representa o conteúdo de texto delimitado por uma tag e é um tipo simples

Comment

Da mesma forma para este tipo

type Comment [ ]byte

VISITE UMA IGREJA EVANGELICA

Page 163: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

ProcInst

A ProcInst representa uma instrução de processamento XML da forma <?target inst?>

type ProcInst struct { Target string Inst [ ]byte}

Diretiva

A diretiva constitui uma diretiva XML da forma <! Text>. Os bytes não incluem o <!and> marcadores.Um programa para imprimir a estrutura da árvore de um documento XML é

/* Parse XML*/package main

import ( "encoding/xml" "fmt" "io/ioutil" "os" "strings")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "file") os.Exit(1) } file := os.Args[1] bytes, err := ioutil.ReadFile(file) checkError(err) r := strings.NewReader(string(bytes))

parser := xml.NewDecoder(r) depth := 0 for { token, err := parser.Token( ) if err != nil { break } switch t := token.(type) { case xml.StartElement: elmt := xml.StartElement(t) name := elmt.Name.Local

printElmt(name, depth) depth++ case xml.EndElement: depth-- elmt := xml.EndElement(t) name := elmt.Name.Local printElmt(name, depth) case xml.CharData: bytes := xml.CharData(t) printElmt("\""+string([ ]byte(bytes))+"\"", depth) case xml.Comment:

VISITE UMA IGREJA EVANGELICA

Page 164: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

printElmt("Comment", depth) case xml.ProcInst: printElmt("ProcInst", depth) case xml.Directive: printElmt("Directive", depth) default: fmt.Println("Unknown") } }}

func printElmt(s string, depth int) { for n := 0; n < depth; n++ { fmt.Print(" ") } fmt.Println(s)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Nota-se que o analisador inclui todos CharData, incluindo os espaços entre as etiquetas.Se executar este programa contra o pessoa estrutura de dados dada anteriormente, produz

person " " name " " family " Newmarch " family " " personal " Jan " personal " " name " " email " [email protected] " email " " email " [email protected]

VISITE UMA IGREJA EVANGELICA

Page 165: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

" email ""person""

Note que como nenhuma outra especificação DTD ou XML tem sido usada, o tokenizador imprime corretamente todo o espaço em branco (um DTD pode especificar que o espaço em branco pode ser ignorada, mas sem que esta suposição não poderá ser feita.)

Há uma armadilha potencial em usar este analisador. Ele reutiliza espaço para strings, de modo que uma vez que você ver um símbolo que você precisa para copiar o seu val você quer se referir a ele mais tarde. Go tem métodos como para fazer uma cópia dos dados. func (c CharData) Copy ( ) CharData para implementar uma cópia de dados

Unmarshalling XML

Go oferece uma função Unmarshal e um método func (*Parser) Unmarshal desempacotar XML em estruturas de dados Go. O Unmarshal unmarshalling não é perfeito: Go e XML são diferentes idiomas.

Nós consideramos um exemplo simples antes de olhar para os detalhes. Tomamos o documento XML dada anteriormente de

<person> <name> <family> Newmarch </family> <personal> Jan </personal> </name> <email type="personal"> [email protected] </email> <email type="work"> [email protected] </email></person>

Nós gostaríamos de mapear este nas estruturas Go Isto requer vários comentários:

type Person struct { Name Name Email [ ]Email}

type Name struct { Family string Personal string}type Email struct { Type string Address string}

1. Unmarshalling usa o pacote reflexão Go. Isto requer que todos os campos por exemplo públicas começar com uma letra maiúscula. Mais cedo versões do Go utilizado sensível a maiúsculas de combinar campos Name tais como o XML string "name" para o campo. Agora, porém, correspondência maiúsculas e minúsculas é usado. Para realizar a prova, os campos de estrutura deve ser marcado para mostrar a sequência de caracteres em contrapartida. Isso muda Person

VISITE UMA IGREJA EVANGELICA

Page 166: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

type Person struct { Name Name `xml:"name"` Email [ ]Email `xml:"email"`}

2. Enquanto a marcação de campos pode append sequências de caracteres XML para campos, não pode fazer isso com os nomes das estruturas. Um campo adicional é necessário, com o nome do campo "XMLName". Isso afeta apenas o nível superior struct, Person

type Person struct { XMLName Name `xml:"person"` Name Name `xml:"name"` Email [ ]Email `xml:"email"`}

3. Etiquetas utilizadas na mapa para uma slice em Go

4. Atributos dentro etiquetas Irá corresponder a campos em uma estrutura de apenas se o campo Go tem a tag ", attr". Isto ocorre com o campo Tipe de Email, Onde combinando o atributo "tipo" do "e-mail" tag requer `Xml:" tipo, attr "`

5. Se uma marca XML não tem atributos e só tem dados de caracteres, em seguida, ele corresponde a um campo string com o mesmo nome (caso sensível, embora). Assim, a marcação xml:"family"com dados de caracteres mapas "Newmarch" para o campo de sequência Family

6. Mas se a marca tem atributos, então ele deve ser mapeado para uma estrutura. Go atribui os dados de caracteres para o campo com tag, Chardata. Isto acontece com o "e-mail" de dados e o campo Address com tag, Chardata

Um programa para desempacotar o documento acima é

/* Unmarshal */

package main

import ( "encoding/xml" "fmt" "os" / /"strings")

type Person struct { XMLName Name `xml:"person"` Name Name `xml:"name"` Email [ ]Email `xml:"email"`}

type Name struct { Family string `xml:"family"` Personal string `xml:"personal"`}

type Email struct { Type string `xml:"type,attr"`

VISITE UMA IGREJA EVANGELICA

Page 167: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Address string `xml:",chardata"`}

func main( ) { str := `<?xml version="1.0" encoding="utf-8"?><person> <name> <family> Newmarch </family> <personal> Jan </personal> </name> <email type="personal"> [email protected] </email> <email type="work"> [email protected] </email></person>`

var person Person

err := xml.Unmarshal([ ]byte(str), &person) checkError(err)

/ / now use the person structure e.g.fmt.Println("Family name: \"" + person.Name.Family + "\"") fmt.Println("Second email address: \"" + person.Email[1].Address + "\"")}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

(Observe os espaços estão corretas.). As regras rígidas são dadas na especificação do pacote.

12,4 Marshalling XML

Go 1 também tem suporte para mobilizar estruturas de dados em um documento XML. A função é

func Marshal(v interface}{) ([ ]byte, error)

Isso foi usado como uma verificação nas duas últimas linhas do programa anterior.

XHTML

O HTML não estar de acordo com a sintaxe XML. Tem marcas sem terminação, como 'em'. XHTML é uma limpeza de HTML para torná-lo compatível com XML. Documentos XHTML podem ser gerenciados usando as técnicas acima para XML.

HTML

Existe algum apoio no pacote XML para lidar com documentos HTML, mesmo que eles não são compatível com XML. O analisador XML discutido anteriormente pode lidar com muitos documentos HTML se for modificada por

parser := xml.NewDecoder(r)parser.Strict = false

VISITE UMA IGREJA EVANGELICA

Page 168: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

parser.AutoClose = xml.HTMLAutoCloseparser.Entity = xml.HTMLEntity

Remote Procedure Call

13.1 Introdução

Soquete e programação HTTP usar um paradigma de passagem de mensagens. Um cliente envia uma mensagem para um servidor, que geralmente envia uma mensagem de volta. Ambos os lados o responsável pela criação de mensagens em um formato entendido por ambos os lados, e na leitura dos dados para fora dessas mensagens.

No entanto, a maioria dos aplicativos autônomos não fazem muito uso de técnicas de passagem de mensagens. Geralmente o preferido mecanismo é o da função (Ou método ou procedimento) chamada. Neste estilo, um programa Irá chamar uma função com uma lista de parâmetros, e no estreitol da chamada de função terá um conjunto de valores de retorno. Estes valores podem ser o valor da função, ou se endereços foram passados como parâmetros, em seguida, o conteúdo desses endereços podem ter sido alterados.

A chamada de procedimento remoto é uma tentativa de trazer esse estilo de programação para o mundo da rede. Assim, um cliente vai fazer o que olha para isso como uma chamada de procedimento normal. O do lado do cliente vai embalar isso em uma mensagem de rede e transferi-lo para o servidor. O servidor Irá descompactar este e transformá-lo de volta para uma chamada de procedimento no lado do servidor. Os resultados desta chamada será embalado para retorno para o cliente.

Esquematicamente parece

Onde os passos são

1. O cliente chama o procedimento stub local. O stub empacota os parâmetros em uma mensagem de rede. Isto é chamado triagem.

2. As funções de rede no kernel O / S são chamados pelo stub para enviar a mensagem.3. O sistema envia a mensagem (s) para o sistema remoto. Isso pode ser orientado a conexão ou

sem conexão.4. Um stub servidor unmarshals os argumentos da mensagem de rede.5. O stub servidor executa uma chamada de procedimento local.6. O procedimento é concluído, retornando a execução para o stub servidor.7. O stub servidor empacota os valores de retorno em uma mensagem de rede.8. As mensagens de retorno são enviados de volta.9. O stub cliente lê as mensagens usando as funções de rede.10. A mensagem é unmarshalled e os valores de retorno são definidos na pilha para o processo local.

Existem dois estilos comuns para a implementação de RPC. A primeira é caracterizada por Sun RPC / ONC e por CORBA. Neste, uma especificação do serviço é dado em alguma linguagem abstrata como

VISITE UMA IGREJA EVANGELICA

Page 169: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

CORBA IDL (Interface Definition Language). Este é então compilados em código para o cliente e para o servidor. O cliente, então, escreve um programa normal que contém chamadas para um procedimento / função / método que é vinculado ao código do cliente gerado. O código do lado do servidor é na verdade um servidor próprio, o que está ligada à implementação do procedimento que você escreve.

Desta forma, o código do lado do cliente é quase idêntico em aparência a uma chamada de procedimento normal. Geralmente há um pouco de código extra para localizar o servidor. Em ONC da Sun, o endereço do servidor deve ser conhecido, em um serviço de nomes CORBA é chamado para encontrar o endereço do servidor; Em Java RMI, o IDL é o próprio Java e um serviço de nomes é usado para encontrar o endereço do serviço.

No segundo estilo, você tem que fazer uso de uma API do cliente especial. Você entrega o nome da função e seus parâmetros para esta biblioteca em lado do cliente. No lado do servidor, você tem que escrever explicitamente o servidor mesmo, bem como a implementação de procedimento remoto.

Esta abordagem é utilizada por muitos sistemas de RPC, tais como Web Services. Ela também é a abordagem usada por RPC Go.

Go RPC

RPC do Go é até agora único a Go. Ele é diferente dos outros sistemas de RPC, assim que um cliente Go só vai conversar com um servidor Go. Ele usa o Sistemas RPC geralmente fazem algumas restrições sobre as funções que podem ser chamadas através da rede. Isso é para que a RPC sistema pode corretamente determinar o que são argumentos de valor a serem enviados, o que são argumentos de referência para receber respostas, e como para sinalizar erros.

No Go, a restrição é que

A função deve ser público (começa com uma letra maiúscula); Tem exatamente dois argumentos, o primeiro é um ponteiro para dados de valor a ser recebido pela

função a partir do cliente, e segunda é um ponteiro para segurar as respostas a serem devolvidos ao cliente, e

Tem um valor de retorno de tipo os.Error

Por exemplo, uma função válida é

F (& T1 e T2) os.Error

A restrição em argumentos significa que você normalmente tem que definir um tipo de estrutura. RPC Go usa a pacote gob para triagem e dados unmarshalling, então os tipos de argumentos tem que seguir as regras do gob como discutido no capítulo anterior.

Devemos seguir o exemplo dado na documentação do Go, como isso ilustra os pontos importantes. O servidor executa dois operações que são triviais que não exigem o "gemido" da RPC, mas são simples de entender. As duas operações devem multiplicar dois números inteiros, e segunda é encontrar o quociente e resto da divisão do primeiro pelo segundo.

Os dois valores a serem manipulados são dadas numa estrutura:

type Values struct { X, Y int}

A soma é apenas uma int, Enquanto que o quociente / restante é outra estrutura

type Quotient struct { Quo, Rem int}

Teremos duas funções, multiplicar e dividir a ser exigível no servidor de RPC. Estas funções deverão ser registrados com o Sistema RPC. A função Register utiliza um único parâmetro, que é uma interface. Então precisamos de um tipo com essas duas funções:

VISITE UMA IGREJA EVANGELICA

Page 170: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) os.Error { *reply = args.A * args.B return nil}

func (t *Arith) Divide(args *Args, quo *Quotient) os.Error { if args.B == 0 { return os.ErrorString("divide by zero") } quo.Quo = args.A / args.B quo.Rem = args.A % args.B return nil}

O tipo subjacente de Arith é dada como int. Isso não importa qualquer tipo poderia ter feito.Um objeto deste tipo podem agora ser registrados usando, em seguida, seus métodos podem ser

chamados pelo sistema RPC.

RPC Servidor HTTP

Qualquer RPC precisa de um mecanismo de transporte para receber mensagens através da rede. Vá pode usar HTTP ou TCP. A vantagem do Mecanismo HTTP é que ele pode alavancar fora da biblioteca suport HTTP. Você precisa adicionar um manipulador de RPC para a camada HTTP que é feito usando HandleHTTP e, em seguida, iniciar um servidor HTTP. O código completo é

/*** ArithServer */

package main

import ( "fmt" "net/rpc" "errors" "net/http")

type Args struct { A, B int}

type Quotient struct { Quo, Rem int}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error { *reply = args.A * args.B return nil}

func (t *Arith) Divide(args *Args, quo *Quotient) error { if args.B == 0 { return errors.New("divide by zero")

VISITE UMA IGREJA EVANGELICA

Page 171: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

} quo.Quo = args.A / args.B quo.Rem = args.A % args.B return nil}

func main( ) {

arith := new(Arith) rpc.Register(arith) rpc.HandleHTTP( )

err := http.ListenAndServe(":1234", nil) if err != nil { fmt.Println(err.Error( )) }}

RPC cliente HTTP

O cliente precisa configurar uma conexão HTTP com o servidor RPC. Ele precisa preparar uma estrutura com os valores a serem enviados, e o endereço de uma variável para armazenar os resultados dentro Então ele pode fazer uma chamada com argumentos:

O nome da função de controle remoto para executar Os valores a serem enviados O endereço de uma variável para armazenar o resultado em

Um cliente que chama ambas as funções do servidor de aritmética é

/*** ArithClient */

package main

import ( "net/rpc" "fmt" "log" "os")

type Args struct { A, B int}

type Quotient struct { Quo, Rem int}

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "server") os.Exit(1) } serverAddress := os.Args[1]

VISITE UMA IGREJA EVANGELICA

Page 172: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

client, err := rpc.DialHTTP("tcp", serverAddress+":1234") if err != nil { log.Fatal("dialing:", err) } / / Synchronous call args := Args{17, 8} var reply int err = client.Call("Arith.Multiply", args, &reply) if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)

var quot Quotient err = client.Call("Arith.Divide", args, ") if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d/%d=%d remainder %d\n", args.A, args.B, quot.Quo, quot.Rem)

}

Servidor RPC TCP

A versão do servidor que usa sockets TCP é

/*** TCPArithServer */

package main

import ( "fmt" "net/rpc" "errors" "net" "os")

type Args struct { A, B int}

type Quotient struct { Quo, Rem int}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error { *reply = args.A * args.B return nil}func (t *Arith) Divide(args *Args, quo *Quotient) error { if args.B == 0 { return errors.New("divide by zero") } quo.Quo = args.A / args.B

VISITE UMA IGREJA EVANGELICA

Page 173: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

quo.Rem = args.A % args.B return nil}

func main( ) {

arith := new(Arith) rpc.Register(arith)

tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

/* This works: rpc.Accept(listener) */ /* and so does this: */ for { conn, err := listener.Accept( ) if err != nil { continue } rpc.ServeConn(conn) }

}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Note-se que a chamada Accept está bloqueando, e só lida com conexões de cliente. Se o servidor quiser fazer outro trabalho, bem como, que deveria Aceitar chamar isso de uma goroutine.

Cliente RPC TCP

Um cliente que usa o servidor TCP e chama ambas as funções do servidor de aritmética é

/*** TCPArithClient */

package main

import ( "net/rpc" "fmt" "log" "os")

type Args struct { A, B int}

VISITE UMA IGREJA EVANGELICA

Page 174: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

type Quotient struct { Quo, Rem int}

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "server:port") os.Exit(1) } service := os.Args[1]

client, err := rpc.Dial("tcp", service) if err != nil { log.Fatal("dialing:", err) } / / Synchronous call args := Args{17, 8} var reply int err = client.Call("Arith.Multiply", args, &reply) if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)

var quot Quotient err = client.Call("Arith.Divide", args, ") if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d/%d=%d remainder %d\n", args.A, args.B, quot.Quo, quot.Rem)

}

Notamos que os tipos de argumentos de valor não são os mesmos no cliente e servidor. No servidor, temos usado Values enquanto em que o cliente foi utilizada Args. Isso não importa, já que estamos seguindo as regras da gob serialização, e os nomes um tipos de campos de duas estruturas "corresponder. Melhor prática de programação diria que os nomes devem ser os mesmos!

No entanto, este não apontar uma possível armadilha em usar Go RPC. Se mudarmos a estrutura no cliente para ser, digamos,

type Values struct {C, B int}

Depois gob não tem problemas: no lado do servidor o unmarshalling Irá ignorar o valor de busca C dada pelo cliente, e usar o padrão

valor zero para A

Usando Vai RPC requer uma aplicação rígida da estabilidade de nomes de campo e tipos de o programador. Notamos que não existe mecanismo de controle de versão para fazer isso, e nenhum mecanismo de para sinalizar eventuais descasamentos.

JSON

Esta seção não acrescenta nada de novo para os conceitos anteriores. Ele só usa um "fio" de formato diferente para os dados, em vez de JSON. Como bisca tais, clientes ou servidores poderia ser escrito em

VISITE UMA IGREJA EVANGELICA

Page 175: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

outros linguagens que entendam soquetes e JSON.Cliente JSON RPCUm cliente que chama ambas as funções do servidor de aritmética é

/* JSONArithCLient */

package main

import ( "net/rpc/jsonrpc" "fmt" "log" "os")

type Args struct { A, B int}

type Quotient struct { Quo, Rem int}

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "server:port") log.Fatal(1) } service := os.Args[1]

client, err := jsonrpc.Dial("tcp", service) if err != nil { log.Fatal("dialing:", err) } / / Synchronous call args := Args{17, 8} var reply int err = client.Call("Arith.Multiply", args, &reply) if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)

var quot Quotient err = client.Call("Arith.Divide", args, ") if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d/%d=%d remainder %d\n", args.A, args.B, quot.Quo, quot.Rem)

}

Servidor JSON RPC

A versão do servidor que usa JSON codificação é

/* JSONArithServer */

VISITE UMA IGREJA EVANGELICA

Page 176: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

package main

import ( "fmt" "net/rpc" "net/rpc/jsonrpc" "os" "net" "errors")/ /import ("fmt"; "rpc"; "os"; "net"; "log"; "http")

type Args struct { A, B int}

type Quotient struct { Quo, Rem int}

type Arith intfunc (t *Arith) Multiply(args *Args, reply *int) error { *reply = args.A * args.B return nil}

func (t *Arith) Divide(args *Args, quo *Quotient) error { if args.B == 0 { return errors.New("divide by zero") } quo.Quo = args.A / args.B quo.Rem = args.A % args.B return nil}

func main( ) {

arith := new(Arith) rpc.Register(arith)

tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

/* This works: rpc.Accept(listener) */ /* and so does this: */for { conn, err := listener.Accept( ) if err != nil { continue } jsonrpc.ServeConn(conn) }

}

VISITE UMA IGREJA EVANGELICA

Page 177: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

canais Rede

Aviso

O pacote netchan está sendo reformulado. Enquanto ele estava em versões anteriores do Go, ele não está em Go 1. Encontra-se disponível no old / netchan pacote, se você ainda precisa dele. Este capítulo descreve esta versão antiga. Não usá-lo para o novo código.

Introdução

Há muitos modelos para o compartilhamento de informações entre os processos de comunicação. Um dos mais elegante é o conceito de Hoare canais. Neste, não há memória compartilhada, de modo que surgir nenhuma das questões relativas ao acesso de memória comum. Em vez disso, um processo de enviará uma mensagem ao longo de um canal para outro processo. Os canais podem ser síncrona ou assíncrona, tampão ou sem buffer.

Um goroutine gera números inteiros de dois para cima. Estes são bombeados para uma série de canais que atuam como peneiros. Cada filtro é distingue-se por um primo diferente, e ele remove do seu fluxo de cada número que é divisível por sua prima. Assim goroutine dos '2 filtra os números pares, enquanto goroutine o '3 'filtra múltiplos de 3. O primeiro número que sai do conjunto atual de filtros deve ser um novo auge, e isso é usado para iniciar um novo filtro com um novo canal.

A eficácia de muitos milhares de goroutines comunicando por muitos milhares de canais depende de quão bem o implementação destas primitivas é feito. Go é projetado para otimizar estes, de modo que este tipo de programa é viável.

Vá também suporta canais distribuídos usando o pacote netchan. Mas as comunicações de rede são milhares de vezes mais lento do que comunicações de canal em um único computador. Executando uma peneira em uma rede através de TCP seria ridiculamente lento. No entanto, ele dá uma opção de programação que pode ser útil em muitas situações.

Modelo de canal de rede da Go é um pouco semelhante em conceito ao modelo RPC: um servidor cria canais e registrá-los com o canal de rede API. Um cliente faz uma pesquisa para os canais em um servidor. Neste ponto, ambos os lados têm um canal compartilhado em que eles podem se comunicar. Note-se que a comunicação é uniidirecional: se você quiser enviar informações para os dois lados, abrir dois canais de um para cada direção.

servidor Canal

A fim de fazer um canal visível para os clientes, você precisa exportar isso. Isto é feito através da criação de um exportador usando NewExporter com nenhuma parâmetros. O servidor chama então para lsiten e lidar com as respostas. Isso leva dois parâmetros, sendo o primeiro o ListenAndServe subjacente mecanismo de transporte, tais como "tcp" e segundo é o endereço de escuta de rede (geralmente apenas um número de porta.

Para cada canal, o servidor cria um canal local normal e, em seguida, chama para ligar está para a rede de canais Export. No momento da exportação, a direção de comunicação deve ser especificado. Clientes procurar canais pelo nome, que é uma string. Isto é especificado para o exportador.

O servidor, em seguida, usa os canais locais na maneira normal, lendo ou escrevendo sobre eles. Nós ilustramos com um servidor de "eco" que lê linhas e enviá-los de volta. Ele precisa de dois canais para esta. O canal que o cliente escreve para nós nomeamos "echoout". No do lado do servidor é um canal de leitura. Da mesma forma, o canal que o cliente lê chamamos "ecoin", o qual é um canal de gravação para o servidor.

VISITE UMA IGREJA EVANGELICA

Page 178: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

O programa servidor é

/* EchoServer */package main

import ( "fmt" "os" "old/netchan")

func main( ) {

/ / exporter, err := netchan.NewExporter("tcp", ":2345") exporter := netchan.NewExporter( ) err := exporter.ListenAndServe("tcp", ":2345") checkError(err)

echoIn := make(chan string) echoOut := make(chan string) exporter.Export("echo-in", echoIn, netchan.Send) exporter.Export("echo-out", echoOut, netchan.Recv) for { fmt.Println("Getting from echoOut") s, ok := <-echoOut if !ok { fmt.Printf("Read from channel failed") os.Exit(1) } fmt.Println("received", s)

fmt.Println("Sending back to echoIn") echoIn <- s fmt.Println("Sent to echoIn") }

}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Nota: no momento da escrita, o servidor será, por vezes, falhar com uma mensagem de erro "exportação netchan: resposta do cliente codificação de erro".

Isso é registrado como Issue 1805

cliente Canal

A fim de encontrar um canal de exportação, o cliente deve importar lo. Isto é criado usando que tem um protocolo e uma rede Importação endereço do serviço de "host: port". Este é, então, usado para importar um canal de rede pelo nome e vinculá-lo a um canal local. Note-se que variáveis de canal são referências, para que você não precisa passar os seus endereços de funções que eles mudam.

A seguir cliente recebe dois canais de e para o servidor de eco, e, em seguida, escreve e lê mensagens de dez:

VISITE UMA IGREJA EVANGELICA

Page 179: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

/* EchoClient */package main

import ( "fmt" "old/netchan" "os")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } service := os.Args[1]

importer, err := netchan.Import("tcp", service) checkError(err)

fmt.Println("Got importer") echoIn := make(chan string) importer.Import("echo-in", echoIn, netchan.Recv, 1) fmt.Println("Imported in")

echoOut := make(chan string) importer.Import("echo-out", echoOut, netchan.Send, 1) fmt.Println("Imported out")

for n := 0; n < 10; n++ { echoOut <- "hello " s, ok := <-echoIn if !ok { fmt.Println("Read failure") break } fmt.Println(s, n) } close(echoOut) os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Canais de canais

O tutorial Go online em http:/ /golang.org/doc/go_tutorial.html tem um exemplo de multiplexação, onde os canais de canais são utilizado. A ideia é que instread de compartilhar um canal, um novo comunicador é dado seu próprio canal para ter uma conversa. Ou seja, um cliente é enviado um canal a partir de um servidor através de um canal partilhado, e usa esse canal particular.

Isso não funciona diretamente com canais da rede: um canal não pode ser enviada através de um canal de rede. Então, temos que ser um pouco mais indireta. Cada vez que um cliente se conecta a um servidor, o servidor cria novos canais de rede e exportá-los com novos nomes. Depois ele envia os nomes

VISITE UMA IGREJA EVANGELICA

Page 180: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

desses novos canais para o cliente o que lhes importa. Ele usa esses novos canais para communications.

Um servidor está

/* EchoChanServer */package main

import ( "fmt" "os" "old/netchan" "strconv")var count int = 0

func main( ) {

exporter := netchan.NewExporter( ) err := exporter.ListenAndServe("tcp", ":2345") checkError(err)

echo := make(chan string) exporter.Export("echo", echo, netchan.Send) for { sCount := strconv.Itoa(count) lock := make(chan string) go handleSession(exporter, sCount, lock)

<-lock echo <- sCount count++ exporter.Drain(-1) }}

func handleSession(exporter *netchan.Exporter, sCount string, lock chan string) { echoIn := make(chan string) exporter.Export("echoIn"+sCount, echoIn, netchan.Send)

echoOut := make(chan string) exporter.Export("echoOut"+sCount, echoOut, netchan.Recv) fmt.Println("made " + "echoOut" + sCount) lock <- "done"

for { s := <-echoOut echoIn <- s } / / should unexport net channels}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

VISITE UMA IGREJA EVANGELICA

Page 181: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

O cliente é

/* EchoChanClient */package main

import ( "fmt" "old/netchan" "os")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "host:port") os.Exit(1) } service := os.Args[1]

importer, err := netchan.Import("tcp", service) checkError(err)

fmt.Println("Got importer") echo := make(chan string) importer.Import("echo", echo, netchan.Recv, 1) fmt.Println("Imported in")

count := <-echo fmt.Println(count)

echoIn := make(chan string) importer.Import("echoIn"+count, echoIn, netchan.Recv, 1)

echoOut := make(chan string) importer.Import("echoOut"+count, echoOut, netchan.Send, 1)

for n := 1; n < 10; n++ { echoOut <- "hello " s := <-echoIn fmt.Println(s, n) } close(echoOut) os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

soquetes Web

Soquetes da Web são projetados para responder a um problema comum com sistemas web: o servidor é incapaz de iniciar ou enviar conteúdo para um agente de usuário como um navegador. Teia soquetes de permitir uma conexão full duplex a ser estabelecido para permitir isso. Go tem quase suporte

VISITE UMA IGREJA EVANGELICA

Page 182: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

completo para eles.

15.1 Aviso

O pacote Web Sockets não está atualmente no principal Go uma árvore e não está incluído nas distribuições atuais. Para usá-lo, você precisa de para instalá-lo por

go get code.google.com/p/go.net/websocket

15.1 Introdução

O modelo websockets mudará para R61 lançamento. Este descreve o novo pacote, não o pacote de r60 e anteriores. Se você fizer R61 não tem, no momento da escrita atualização semanal, usar hg pull; hg update weekly para baixá-lo.

O modelo padrão de interação entre um agente de usuário da web como um navegador e um servidor web como o Apache é que o usuário agente faz solicitações HTTP e servidor faz uma única resposta para cada uma delas. No caso de um navegador, o pedido é feito por clicar em um link, digitar uma URL na barra de endereços, clicando nos botões frente ou para trás, etc A resposta é tratada como uma nova página e é carregado em uma janela do navegador.

Este modelo tradicional tem muitos inconvenientes. A primeira é de que cada pedido abre e fecha uma nova ligação TCP. HTTP 1.1 resolvido isso, permitindo que as conexões persistentes, de modo que uma conexão pode ser mantida aberta por um curto período para permitir múltiplas pedidos (por exemplo, imagens) a ser feito no mesmo servidor.

Enquanto HTTP 1.1 conexões persistentes aliviar o problema de carregamento lento de uma página com muitos gráficos, ele não melhorar o modelo de interação. Mesmo com as formas, o modelo ainda é o de submeter o formulário e exibir a resposta como uma nova página.

Java Script ajuda em permitir a verificação a ser realizada em dados do formulário antes da apresentação de erro, mas não muda o modelo.

AJAX (Asynchronous Java Script and XML) fez um avanço significativo para o modelo de interação do usuário. Isto permite que um navegador de fazer um pedido e usar apenas a resposta para atualizar a exibição no local usando o Document Object Model (DOM) HTML. Mas novamente o modelo de interação é o mesmo. AJAX só afeta o modo como o navegador gerencia as páginas retornadas. Não há extras explícita apoio em Go para AJAX, como nenhum é necessário: o servidor HTTP só vê uma solicitação HTTP POST comum com, possivelmente, alguns XML ou JSON dados, e esta pode ser tratada com o uso de técnicas já discutidas.

Todos estes ainda são navegador para comunicação do servidor. O que está faltando é o servidor iniciado comunicações para o navegador. Esta lata ser preenchido por soquetes da Web: o navegador (ou qualquer agente do usuário) mantém aberta uma conexão TCP de longa duração a um servidor Web Sockets.

Conexão TCP permite que cada lado para enviar pacotes arbitrários, portanto, qualquer protocolo de aplicação pode ser utilizado em um soquete web.

O Como um websocket é iniciado é pelo agente do usuário enviando uma solicitação HTTP especial que diz "mudar para soquetes web". O TCP conexão subjacente a solicitação HTTP é mantida aberta, mas ambos agente do usuário e chave do servidor para utilizar o protocolo soquetes web em vez de começar uma resposta HTTP e fechar o socket.

Note-se que ele ainda é o navegador ou agente de usuário que inicia a conexão de soquete web. O navegador não executar um servidor TCP de própria. Enquanto a especificação é complexo, o protocolo é projetado para ser bastante fácil de usar. O cliente abre uma conexão HTTP e, em seguida, substitui o protocolo HTTP com o seu próprio protocolo WS, reutilizando a mesma conexão TCP.

Servidor Web socket

Um servidor de soquete web começa por ser um servidor HTTP, aceitando conexões TCP e lidar com as solicitações HTTP no TCP conexão. Quando uma solicitação vem em que alterna essa conexão com um ser uma conexão de soquete web, o manipulador de protocolo é mudou de um manipulador HTTP para um manipulador WebSocket. Por isso, é apenas essa conexão TCP que recebe o seu papel mudou: o servidor continua a ser um servidor de HTTP para pedidos de outros, enquanto que a tomada de TCP subjacente que uma ligação é utilizada como uma tomada de teia.

Um dos servidores simples HHTP discutimos no Capítulo 8: manipuladores vários HTTP registrados

VISITE UMA IGREJA EVANGELICA

Page 183: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

como um manipulador de arquivo ou uma função manipulador. Para lidar com os pedidos de soquete web simplesmente registrar um tipo diferente de manipulador um manipulador tomada web. Qual manipulador a usos servidor é baseado no padrão de URL. Por exemplo, um manipulador de arquivo pode ser registrado para "/", um manipulador de função para "/ cgibin / ..." e um manipulador de soquetes para "/ ws".

Um servidor HTTP que só está à espera de ser usado para soquetes web pode ser executado por

func main( ) { http.Handle("/", websocket.Handler(WSHandler)) err := http.ListenAndServe(":12345", nil) checkError(err)}

Um servidor mais complexa pode lidar com ambos os pedidos de soquete web HTTP e simplesmente adicionando em mais manipuladores.

O objeto Message

HTTP é um protocolo de fluxo. Soquetes da Web são baseados em quadro. Você prepara um bloco de dados (de qualquer tamanho) e enviá-lo como um conjunto de quadros. Os quadros podem conter strings em codificação UTF8 ou uma sequência de bytes.

A maneira mais simples de usar soquetes web é apenas para preparar um bloco de dados e pedir a biblioteca websocket Go para empacotá-lo como um conjunto de dados do quadro, enviá-los através do fio e recebê-lo como o mesmo bloco. O pacote contém um objeto de conveniência websocket para fazer exatamente isso. O objeto Message tem dois métodos, Send e Receive que dê uma websocket como primeiro parâmetro. O segundo parâmetro é o endereço de uma variável para armazenar dados em, ou os dados a serem enviados. Código para enviar dados de cadeia ficaria como

msgToSend := "Hello" err := websocket.Message.Send(ws, msgToSend)

var msgToReceive string err := websocket.Message.Receive(conn, &msgToReceive)

Código para enviar dados byte seria semelhante

dataToSend := [ ]byte{0, 1, 2} err := websocket.Message.Send(ws, dataToSend)

var dataToReceive [ ]byte err := websocket.Message.Receive(conn, &dataToReceive)

Um servidor de echo para enviar e receber dados de cadeia é dado abaixo. Notese que em ambos os lados soquetes web pode iniciar o envio de mensagens, e neste servidor que enviar mensagens a partir do servidor para um cliente quando ele se conecta (enviar / receber) em vez do mais normal de receber / enviar servidor. O servidor é

/* EchoServer */package main

import ( "fmt" "net/http" "os" / / "io" "code.google.com/p/go.net/websocket")

VISITE UMA IGREJA EVANGELICA

Page 184: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

func Echo(ws *websocket.Conn) { fmt.Println("Echoing")

for n := 0; n < 10; n++ { msg := "Hello " + string(n+48) fmt.Println("Sending to client: " + msg) err := websocket.Message.Send(ws, msg) if err != nil { fmt.Println("Can't send") break }

var reply string err = websocket.Message.Receive(ws, &reply) if err != nil { fmt.Println("Can't receive") break } fmt.Println("Received back from client: " + reply) }}

func main( ) {

http.Handle("/", websocket.Handler(Echo)) err := http.ListenAndServe(":12345", nil) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

O cliente conversa com o servidor

/* EchoClient */package main

import ( "code.google.com/p/go.net/websocket" "fmt" "io" "os")

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "ws:/ /host:port") os.Exit(1) } service := os.Args[1]

conn, err := websocket.Dial(service, "", "http:/ /localhost") checkError(err)

VISITE UMA IGREJA EVANGELICA

Page 185: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

var msg string for { err := websocket.Message.Receive(conn, &msg) if err != nil { if err == io.EOF { / / graceful shutdown by server break } fmt.Println("Couldn't receive msg " + err.Error( )) break } fmt.Println("Received from server: " + msg) / / return the msg err = websocket.Message.Send(conn, msg) if err != nil { fmt.Println("Coduln't return msg") break } } os.Exit(0)}func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

A url para o cliente em execução na mesma máquina que o servidor deve ser ws :/ / local host: 12345 /

O objeto JSON

Espera-se que muitos clientes e servidores WebSocket trocarão dados em formato JSON. Para os programas de Go, isto significa que a Go objeto será empacotado em formato JSON, conforme descrito no Capítulo 4: seriação e depois enviado como uma string UTF8, enquanto o receptor Irá ler essa string e desempacota-lo de volta em um objeto Go.

O websocket conveniência objeto JSON vai fazer isso por você. Tem métodos Send e Receive para enviar e receber dados, basta enviar como o Mensagem objeto.

Um cliente que envia uma Person objeto no formato JSON é

/* PersonClientJSON */package main

import ( "code.google.com/p/go.net/websocket" "fmt" "os")

type Person struct { Name string Emails [ ]string}

func main( ) {

VISITE UMA IGREJA EVANGELICA

Page 186: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "ws:/ /host:port") os.Exit(1) } service := os.Args[1]

conn, err := websocket.Dial(service, "", "http:/ /localhost") checkError(err)

person := Person{Name: "Jan", Emails: [ ]string{"[email protected]", "[email protected]"}, }

err = websocket.JSON.Send(conn, person) if err != nil { fmt.Println("Couldn't send msg " + err.Error( )) } os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

O servidor de respostas é

/* PersonServerJSON */package main

import ( "code.google.com/p/go.net/websocket" "fmt" "net/http" "os")

type Person struct { Name string Emails [ ]string}

func ReceivePerson(ws *websocket.Conn) { var person Person err := websocket.JSON.Receive(ws, &person) if err != nil { fmt.Println("Can't receive") } else {

fmt.Println("Name: " + person.Name) for _, e := range person.Emails { fmt.Println("An email: " + e) } }}

VISITE UMA IGREJA EVANGELICA

Page 187: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

func main( ) {

http.Handle("/", websocket.Handler(ReceivePerson)) err := http.ListenAndServe(":12345", nil) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

O Codec tipo

O Message e JSON objetos são ambos instâncias do tipo Codec. Este tipo é definido pela

type Codec struct { Marshal func(v interface{ }) (data [ ]byte, payloadType byte, err os.Error) Unmarshal func(data [ ]byte, payloadType byte, v interface{ }) (err os.Error)}

O tipo Codec implementa o Send e Receive métodos utilizados anteriormente.

É provável que websockets também Irá ser utilizado para a troca de dados XML. Nós podemos construir um XML Codec objeto envolvendo o XML marechal e métodos desempacotar discutidos Capítulo 12: XML para dar uma adequada objeto.

Podemos criar um pacote XML CODE da seguinte forma:

package xmlcodec

import ( "encoding/xml" "code.google.com/p/go.net/websocket")

func xmlMarshal(v interface{ }) (msg [ ]byte, payloadType byte, err error) { / /buff := &bytes.Buffer{ } msg, err = xml.Marshal(v) / /msgRet := buff.Bytes( ) return msg, websocket.TextFrame, nil}

func xmlUnmarshal(msg [ ]byte, payloadType byte, v interface{ }) (err error) { / / r := bytes.NewBuffer(msg) err = xml.Unmarshal(msg, v) return err}

var XMLCodec = websocket.Codec{xmlMarshal, xmlUnmarshal}

Podemos, então, publicando objetos Go como uma Personkem um documento XML e enviálo a partir de um cliente para um servidor por

VISITE UMA IGREJA EVANGELICA

Page 188: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

/* PersonClientXML */package main

import ( "code.google.com/p/go.net/websocket" "fmt" "os" "xmlcodec")

type Person struct { Name string Emails [ ]string}

func main( ) { if len(os.Args) != 2 { fmt.Println("Usage: ", os.Args[0], "ws:/ /host:port") os.Exit(1) } service := os.Args[1]

conn, err := websocket.Dial(service, "", "http:/ /localhost") checkError(err)

person := Person{Name: "Jan", Emails: [ ]string{"[email protected]", "[email protected]"}, }

err = xmlcodec.XMLCodec.Send(conn, person) if err != nil { fmt.Println("Couldn't send msg " + err.Error( )) } os.Exit(0)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

Um servidor que recebe este e apenas imprime informações para o console é

package main

import ( "code.google.com/p/go.net/websocket" "fmt" "net/http" "os" "xmlcodec")

type Person struct { Name string

VISITE UMA IGREJA EVANGELICA

Page 189: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Emails [ ]string}

func ReceivePerson(ws *websocket.Conn) { var person Person err := xmlcodec.XMLCodec.Receive(ws, &person) if err != nil { fmt.Println("Can't receive") } else {

fmt.Println("Name: " + person.Name) for _, e := range person.Emails { fmt.Println("An email: " + e) } }}

func main( ) {

http.Handle("/", websocket.Handler(ReceivePerson)) err := http.ListenAndServe(":12345", nil) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

soquetes Web mais de TLS

A tomada de web pode ser construído sobre uma tomada TLS segura. Discutimos em Capítulo 8: HTTP como usar uma tomada usando o TLS certificados do Capítulo 7: Segurança . Isso é usado para inalterada soquetes web. Isto é, usamos http.ListenAndServeTLS para um web socket. Em vez de http. ListenAndServe

Aqui está o servidor de eco usando TLS

/* EchoServer */package main

import ( "code.google.com/p/go.net/websocket" "fmt" "net/http" "os")

func Echo(ws *websocket.Conn) { fmt.Println("Echoing")

for n := 0; n < 10; n++ { msg := "Hello " + string(n+48) fmt.Println("Sending to client: " + msg) err := websocket.Message.Send(ws, msg) if err != nil { fmt.Println("Can't send")

VISITE UMA IGREJA EVANGELICA

Page 190: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

break }

var reply string err = websocket.Message.Receive(ws, &reply) if err != nil { fmt.Println("Can't receive") break } fmt.Println("Received back from client: " + reply) }}

func main( ) {

http.Handle("/", websocket.Handler(Echo)) err := http.ListenAndServeTLS(":12345", "jan.newmarch.name.pem", "private.pem", nil) checkError(err)}

func checkError(err error) { if err != nil { fmt.Println("Fatal error ", err.Error( )) os.Exit(1) }}

O cliente é o mesmo cliente de eco como antes. Tudo o que muda é a url, que utiliza o esquema de "WSS" em vez do "ws" esquema:

EchoClient WSS :/ / local host: 12345 /

VISITE UMA IGREJA EVANGELICA

Page 191: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

MODULO 2 LINGUAGEM GO

VISITE UMA IGREJA EVANGELICA

Page 192: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

INTRODUÇÃO A LINGUAGEM GO

Código menos, compilar mais rápido, mais rápido executar => ter mais diversão!

Este texto apresenta o tratamento mais abrangente da linguagem de programação Go você pode encontrar. Inspira-se em todo o espectro de fontes Go disponíveis: documentação e blogs, livros, artirás, áudio e vídeo, e minha própria experiência em engenharia de software e linguagens de programação de ensino e bases de dados, organizando os conceitos e técnicas de uma forma sistemática online.

Vários pesquisadores e desenvolvedores da Google experimentou a frustração com os processos de desenvolvimento de software dentro da empresa, particularmente usando C + + para escrever software de servidor de grande porte. Os binários tendem a ser enorme e levou muito tempo para compilar, e da própria linguagem era muito antiga. Um monte de ideias e mudanças no hardware que surgiram no último par de décadas não tiveram a chance de influenciar C + +. Assim, os pesquisadores sentou-se com uma folha de papel e tentou projetar uma linguagem que Iria resolver os problemas que tinham:

1.Software precisam ser construído rapidamente,2.A linguagem deve rodar bem em hardware multicores moderno,3.A linguagem deve funcionar bem em um ambiente de rede,4.A linguagem deve ser um prazer de usar.

E assim nasceu "Go", uma língua que tem a sensação de uma linguagem dinâmica como Python ou Ruby, mas tem o desempenho e a segurança de linguagens como C ou Java.

Go procura reinventar programação no mais prático de formas: a sua não fundamentalmente uma nova linguagem, ele constrói e melhora muito na sintaxe estilo C # / Java / C existente. Propõe interfaces para programação orientada a objetos e goroutines / canais para programação concorrente e paralela.

Para aqueles de vocês que estão familiarizados com C ou as linguagens orientadas a objeto atuais, vamos comparar os conceitos em Go com os conceitos correspondentes em linguagens.

Go é simples o suficiente para caber em sua cabeça, o que não pode ser dito de C + + ou Java, a barreira de entrada é baixo, em comparação com, por exemplo Scala (a língua concorrente Java). Go é um moderno C.

A maioria dos códigos-exemplos e exercícios fornecidos interagir com o console, que não é uma surpresa, já que Go é em essência uma língua sistemas. Fornece um framework de interface gráfica do usuário (GUI), que é independente de plataforma é uma tarefa enorme.

Mas nesta época a web e seus protocolos estão onipresente, de modo a fornecer uma interface gráfica em alguns exemplos e exercícios, vamos utilizar poderosos pacotes http e modelo embora.

Toda linguagem contém novas características e omite recurso favorito de alguém. Go foi projetado com um olho na felicidade de programação, a velocidade de compilação, ortogonalidade dos conceitos, e da necessidade de oferecer suporte a recursos como a concorrência e coleta de lixo. O seu recurso favorito pode estar faltando porque ele não se encaixa, porque afeta a velocidade de compilação ou clareza de design, ou porque faria a modelo fundamental sistema muito difícil.

Se te incomoda que Go está faltando a função X, por favor, perdoemos e investigar as características que Go tem. Você pode achar que eles compensar em maneiras interessantes para a falta de X.

VISITE UMA IGREJA EVANGELICA

Page 193: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Origens e evolução

Ano da nascimento do Go era de 2007, e no ano de seu lançamento público foi de 2009. O projeto inicial em Go começou em 21 de setembro de 2007, como um projeto de 20% a tempo parcial em Google Inc.

Sendo um projeto de código aberto, a partir de então uma comunidade crescendo rapidamente formou-se o que acelerou muito o desenvolvimento e uso da língua. Desde o seu lançamento, mais de 200 colaboradores não-Google ter apresentado mais de 1000 alterações ao núcleo Go, ao longo dos últimos 18 meses, 150 desenvolvedores contribuíram novo código. Esta é uma das maiores equipes de código aberto do mundo.

Go iniciou um monte de agitação quando foi lançado publicamente e em 08 de janeiro de 2010 Go foi declarado "língua do ano 2009 'pelo Tiobe (ranking mundial popularidade de linguagens de programação). Neste ranking que atingiu o seu valor máximo em fevereiro de 2010.

Ano Vencedor2010 Python2009 Go2008 C2007 Python2006 Rubi2005 Java2004 PHP2003, C + +

Go Linguagem de Programação do ano 2009 no Tiobe

Desde maio de 2010 Go é usado na produção do Google para a infraestrutura de back-end, por exemplo, programas de escrita para a administração de ambientes complexos. Isso prova que o Google quer investir nela, e que a língua é a produção digna.

O site principal é http:/ /golang.org/ é o site oficial do projeto, onde você também pode escrever e compilar seus códigos Go on-line, para aprendizado.

1.2 Principais características, contexto e as razões para o desenvolvimento de uma nova linguagem

1.2.1 Línguas que influenciaram Go

Go é uma linguagem projetado a partir do zero, como um "C para o século 21". Pertence à-família C, como C + +, Java e C #, e é inspirado em muitas línguas criadas e usadas por seus designers.

Houve contribuição significativa da família Pascal / Modula / Oberon e de Python.Por seu mecanismo de concorrência que tem por base a experiência adquirida com Limbo e

Newsqueak, que se foram inspirados pela teoria CSP de Tony Hoare (comunicação de processos sequenciais), o que é essencialmente o mesmo mecanismo usado pela linguagem Erlang.

É uma linguagem completamente open-source, distribuído com uma licença BSD, por isso pode ser usado por todos, mesmo para fins comerciais sem uma taxa, e pode até mesmo ser alterado por outros.

A semelhança com o C-sintaxe foi mantida de modo a ser imediatamente familiarizado com a maioria dos desenvolvedores, porém comparando com C / C + + a sintaxe é bastante simplificado e tornado mais conciso e limpo.

A figura a seguir mostra algumas das influências:

1.2.2 Por uma nova linguagem?

- C / C + + não evoluíram com a paisagem de computação, nenhum grande língua sistemas surgiu em mais de uma década: para que haja uma clara necessidade de uma nova linguagem de sistemas, adequada às necessidades da nossa era da computação.

- Em contraste com o poder de computação, desenvolvimento de software não é consideravelmente mais rápido ou mais sucesso (considerando o número de projetos fracassados) e aplicações ainda crescer em tamanho, assim que uma nova linguagem de baixo nível, mas equipado com conceitos mais elevados, é

VISITE UMA IGREJA EVANGELICA

Page 194: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

necessário.- Antes de Go um desenvolvedor tinha que escolher entre a execução rápida, mas de construção lento

e não eficiente (como C + +), a compilação eficiente (mas não a execução tão rápido, como NET ou Java.), Ou a facilidade de programação (mas execução mais lenta, como a dinâmica idiomas): Go é uma tentativa de combinar os três desejos: eficiente e compilação, portanto, rápido, execução rápida, facilidade de programação.

Necessidade de paralelismo na computação

Vários fatores explicam a necessidade do processamento paralelo. O principal deles trata da busca por maior desempenho. As diversas áreas nas quais a computação se aplica, sejam científicas, industriais ou militares, requerem cada vez mais poder computacional, em virtude dos algoritmos complexos que são utilizados e do tamanho do conjunto de dados a ser processado.

Além disso, várias aplicações são inerentemente paralelas, e perde-se desempenho pela necessidade de torná-las sequenciais. O chamado "gargalo de von Neumann", segundo Almasi, tem diminuído a produtividade do programador, daí a necessidade de novas maneiras de organização do processamento computacional.

Contudo, substituir uma filosofia computacional já firmemente estabelecida pelas várias décadas de existência da computação, como é a filosofia de von Neumann, é algo que representa um obstáculo de dimensões muito grandes, e que de certa maneira dificulta a difusão da computação paralela.

A necessidade de processamento massivo e de paralelismo leva a uma outra questão, relativa ao compartilhamento de memória em sistemas paralelos. Como os diversos processadores utilizam uma mesma memória física, tal tarefa não é trivial e, em geral, limita a escalabilidade do sistema.

Neles, a comunicação é realizada em hardware mediante a troca de mensagens. Isso fica bem claro no nível da aplicação quando o modelo de programação é orientado segundo essa lógica. Porém, embora tal linha de comunicação seja bastante natural, ela pode certamente se mostrar extremamente complicadas em diversas situações, como aquelas nas quais os padrões de interação e compartilhamento de dados são mais complexos e possuem escalas maiores. Além disso, tal lógica exige um maior nível de treinamento por parte dos programadores, o quem nem sempre acontece.

De fato, quando passamos para a dimensão do software paralelo, temos dois paradigmas clássicos de programação paralela nesse sentido: o da troca de mensagens, mencionado anteriormente, e o compartilhamento de memória.

A programação no paradigma de memória compartilhada é considerada mais simples, pois evita que o programador tenha que se preocupar com a comunicação entre processos, através da troca explícita de mensagens. Para realizar comunicação, um processo apenas escreve dados na memória para serem lidos por todos os outros. Para sincronização, seções críticas podem ser usadas, com a utilização de semáforos ou monitores para garantir exclusão mútua.

No paradigma de troca de mensagens a comunicação é realizada através de primitivas que explicitamente controlam o deslocamento dos dados. Troca de mensagens apresenta várias dificuldades, entre elas controle de fluxo, mensagens perdidas, controle do buffer (buffering) e bloqueio (blocking). Embora várias soluções tenham sido propostas, programação com troca de mensagens permanece complicada.

Em resumo, os multicomputadores são simples de construir, mas difíceis de programar, enquanto os multiprocessadores são difíceis de construir mais simples de programar. Além disso, com a grande demanda por sistemas paralelos com capacidade de suportar grandes volumes de dados, torna-se evidente a necessidade de maneiras de tornar essa tarefa o mais simples possível para o programador

Alvos da língua

A meta principal era combinar a eficácia, rapidez e segurança de uma linguagem fortemente e compilado estaticamente com a facilidade de programação de uma linguagem dinâmica, de modo a tornar a programação mais divertido novamente.

Assim, a linguagem é de tipo seguro (tipy safe), e é também a memória de segura (memory safe): ponteiros são usados em Go, mas sem a possibilidade do incomodo da aritmética de ponteiro.

Outro alvo foi a de que ele deve dar um excelente suporte para rede-comunicação, concorrência e paralelismo, a fim de tirar o máximo proveito de máquinas distribuídas e multicores. Ele é implementado através dos conceitos de goroutines, que são muito leves-threads, e os canais de comunicação entre eles.

Eles são implementados como pilhas crescentes (pilhas segmentados) e multiplexação de goroutines em threads é feito automaticamente.

VISITE UMA IGREJA EVANGELICA

Page 195: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Este é certamente o grande reduto de Go, dada a crescente importância dos computadores multicores e multiprocessadores, e falta de apoio para que em linguagens de programação existentes.

De extrema importância também foi a velocidade de compilação e links para código de máquina. Esta nasceu da frustração com a compilação dos tempos dos projetos + +, muito utilizadas na infraestrutura do Google. Isso por si só deve dar um enorme impulso para a produtividade do desenvolvedor e dar origem a um ciclo de desenvolvimento teste-código mais apertado.

Dependência de gestão é uma grande parte do desenvolvimento de software hoje, mas os "arquivos de cabeçalho" de línguas na tradição C estão causando sobrecarga considerável levando a construir momentos de horas para os grandes projetos. É necessária uma análise de dependência rígida e limpa e rápida compilação. Isto é o que Go oferece com o seu modelo de pacote: dependências explícitas para permitir constrói mais rápido. O modelo de pacote de Go prevê excelente escalabilidade.

Toda a biblioteca padrão Go compila em menos de 20 segundos; projetos típicos compilarem meio segundo: este rápido processo de compilação, ainda mais rápido que C ou Fortran. Até agora este foi considerado como um dos grandes benefícios de linguagens dinâmicas, pois o muito tempo gasto para compilação / ligação de C + + não pode ser ignorada, mas com Go isso não é Irrisório, assim com Go temos a mesma produtividade no ciclo de desenvolvimento de um script ou linguagem dinâmica.

Por outro lado, a velocidade de execução do código nativo deve ser comparável ao C / C + +.Porque os chamados vazamento de memória são um problema de longa data de C + +, os designers

de Go decidiram que a gestão de memória não deve ser da responsabilidade do desenvolvedor. Assim, embora Go executa código nativo, ele é executado em uma espécie de tempo de execução, que cuida de uma coleta de lixo eficiente e rápido. A coleta de lixo, embora difícil de implementar para esse tipo de problemas, foi considerada crucial para o desenvolvimento dos aplicativos simultâneos do futuro. Ele também tem uma capacidade de execução de reflexão embutida.

O instalador Go fornece um sistema de implantação fácil para os pacotes externos.Além disso, há suporte para utilização das bibliotecas C.

orientadores princípios de design

Go tenta reduzir a digitação, desordem e complexidade na codificação através de uma quantidade mínima de palavras-chave (25). Juntamente com a sintaxe limpa, regular e concisa, este aumenta a velocidade de compilação, porque as palavras-chave pode ser analisado sem uma tabela de símbolos.

Estes aspectos reduzir o número de linhas de código necessárias, mesmo em comparação com Java.Go tem uma abordagem minimalista: tende a haver apenas uma ou duas formas de fazer as coisas,

para que a leitura de código de outros personagens geralmente é muito fácil, nós sabemos legibilidade do código é de extrema importância para a engenharia de software.

Os conceitos de design da linguagem Go não fica no caminho do outro, eles não somam complexidade uns aos outros, ou seja, eles são ortogonais.

É essencialmente tem uma estrutura de linguagem processual e imperativo, construído com a concorrência em mente. Tem uma abordagem diferente de orientação a objetos, diferente de Java e C + +, porque ele não tem o conceito de classes e herança. No entanto ele possui um conceito de interfaces, com a qual muito do complexo polimorfismo que é ignorado pela maioria dos programadores de linguagens orientadas a objetos, pode ser realizado de uma maneira muito simples.

Go tem um sistema tipo clara e expressiva, mas é leve e sem hierarquia. Go pode ser chamado de uma linguagem híbrida.

Orientação a objetos é considerada "pesada", levando ao desenvolvimento muitas vezes complicado construir grandes hierarquias de tipo, e assim não é compatível com a meta de velocidade da linguagem Go.

As funções são o bloco de construção básico em Go, e seu uso é muito versátil, apresentando aspectos fundamentais de uma linguagem funcional.

É tipagem estática, assim, uma linguagem segura, e compila para código nativo, por isso tem uma execução muito eficiente.

Ele é fortemente tipado: tipo implícito de conversões não são permitidos. Contem certas características de uma linguagem de tipagem dinâmica.

Go tem suporte para cross-compilação, ou seja a similar a portabilidade de Java e .net: por exemplo, o

VISITE UMA IGREJA EVANGELICA

Page 196: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

desenvolvimento de uma máquina Linux para um aplicativo que Irá executar no Windows. É a primeira linguagem de programação em que UTF-8 pode ser usado, não só em strings, mas também no código do programa.

Ao sair de um outro idioma para Go, você pode caro na armadilha de tentar programar em Go como você fez no seu X- língua, principalmente de classe ou linguagens orientadas a herança, como Java, C #, Objective C, Python, Ruby). Go é construído sobre um modelo diferente, de modo a tentar mover o código de X para Go esse código tem que ser repensado. Se você tomar um ponto de vista mais alto e começar a analisar o problema de dentro da mentalidade Go, muitas vezes essa abordagem diferente leva a uma solução elegante, idiomática e multithread.

ORIENTAÇÃO A OBJETOS EM GO

Go é uma linguagem orientada a objeto? Sim e não. Embora Go tem tipos e métodos e permite um estilo orientado a objetos de programação, não há hierarquia de tipos. O conceito de "Interface" no Go oferece uma abordagem diferente, que nós acreditamos que é fácil de usar e de certa forma mais geral.

Um tipo Go satisfaz uma interface através da implementação dos métodos dessa interface, nada mais. Essa propriedade permite que interfaces para ser definido e usado sem ter que modificar o código existente. Ele permite que um tipo de digitação estrutural que promove a separação de interesses e melhora código reuso, e torna mais fácil para construir sobre os padrões que emergem como o código se desenvolve. A semântica de interfaces é uma das principais razões para a agilidade e sensação de leveza.

Go não suporta sobrecarga de métodos e operadores. Método envio é simplificada se não precisa fazer tipo de correspondência também. A experiência com outros idiomas nos disse que ter uma variedade de métodos com o mesmo nome mas assinaturas diferentes é ocasionalmente útil, mas que ele também poderia ser confuso e frágil na prática. Correspondência apenas pelo nome e exigindo consistência nos tipos era uma decisão importante simplificação no sistema de tipo de Go. Em relação a sobrecarga de operador, parece mais uma conveniência do que uma exigência absoluta. Mais uma vez, o que é mais simples, sem ele.

Há também maneiras de incorporar tipos em outros tipos de fornecer algo análogo, mas não idêntico a subclasse. Além disso, os métodos de Go são mais gerais do que em C + + ou Java: eles podem ser definidos para qualquer tipo de dados, mesmo tipos internos, como a planície, inteiros "desembalados". Eles não estão restreitos a estruturas (classes).

Além disso, a falta de hierarquia de tipos faz com que "objetos" em Go se sentir muito mais leve do que em linguagens como C + + ou Java. Os três aspectos importantes das línguas orientadas a objetos são encapsulamento, herança e polimorfismo, como eles estão previstos no Go?

i) Encapsulation (ocultamento de dados): por definição geral encapsulamento consiste na separação de aspectos internos e externos de um objeto. Este mecanismo é utilizado amplamente para impedir o acesso direto ao estado de um objeto (seus atributos), Go disponibiliza externamente apenas os métodos que alteram estes estados ao contrário de outras linguagens OO, onde há 4 ou mais-níveis de acesso, Go simplifica isso para apenas 2 (o famoso Public-privat do Go):

1) escopo do pacote: "objeto" só é conhecida em seu próprio pacote, como? ele começa com uma letra minúscula (privado).

2) exportado: "objeto" é visível do lado de fora de seu pacote, como? ele começa com uma letra maiúscula (Publico)

Um tipo só pode ter métodos definidos em seu próprio pacote.ii) Herança: como conceito geral herança significa o mecanismo pelo qual uma “classe (subclasse)”

pode estender outra “classe (superclasse)”, aproveitando seus comportamentos (métodos) e estados possíveis atributos. Há herança múltipla quando uma subclasse possui mais de uma superclasse. Um exemplo de herança: Mamífero é superclasse de Humano. Ou seja, um Humano é um mamífero. Como Go faz? composição: incorporação de um (ou mais) tipo (s) com o comportamento desejado (campos e métodos); herança múltipla é possível através da incorporação (de forma muito mais fácil que C++ e Java). Programação orientada a objetos, pelo menos nas línguas mais conhecidas, envolve muita discussão sobre as relações entre os tipos de relacionamentos que muitas vezes poderiam ser derivados automaticamente. Go tem uma abordagem diferente. Em vez de exigir que o programador declarar de antemão que dois tipos estão relacionados, em Go um tipo satisfaz automaticamente qualquer interface que especifica um

VISITE UMA IGREJA EVANGELICA

Page 197: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

subconjunto de seus métodos. Além de reduzir a escrituração, esta abordagem tem vantagens reais.iii) Polimorfismo: como conceito geral permite que uma referência de um tipo de uma” superclasse”

tenha seu comportamento alterado de acordo com a instância da “classe filha” a ela associada. Go usa as interfaces: uma variável de um tipo pode ser atribuído a uma variável de qualquer interface que ele implementa. Tipos e interfaces são de baixo acoplamento, mais uma vez a herança múltipla é possível através da implementação de várias interfaces. Interfaces da Go não são uma variante # interfaces Java ou C, eles são muito mais: eles são independentes e são fundamentais para a programação em grande escala e design adaptável, evolutiva.

Usos da linguagem

Go foi originalmente concebido como uma linguagem de programação de sistemas, para ser usado no servidores web mundial do Google, arquitetura de armazenamento e assim por diante. Para certos domínios, como sistemas distribuídos de alto desempenho Go já provou ser uma linguagem mais produtiva do que a maioria dos outros e fazendo concorrência maciça fácil, por isso deve ser um bom projeto para desenvolvimento em servidores. Go é usados internamente no Google para dever cada vez mais pesado de aplicações distribuídas.

Mas também é uma linguagem de programação geral, e muito útil para a resolução de problemas de processamento de texto, fazendo interfaces ou aplicativos no mesmo script-like. No entanto o uso de Go não é adequado para software em tempo real por causa da coleta de lixo e de alocação de memória automática.

Uma série de características que podem ser encontrados na maioria dos línguas orientadas a objeto modernas estão em falta no Go, alguns deles ainda pode ser implementado no futuro.

- Sem função ou sobrecarga de operadores: isso é para simplificar o design.- Não há conversões implícitas por design, para evitar os muitos erros e confusões decorrentes de C /

C + +- Não há classes e tipo de herança: Go tem uma outra abordagem para o design orientado a objeto.- Nenhum tipo de variante: quase a mesma funcionalidade é realizado através de interfaces.- Sem código de carregamento dinâmico- Não há bibliotecas dinâmicas- Não há genéricos- Sem exceções (embora recover/panic é um conceito similar)- Não há assertions- Não há variáveis imutáveis

MUDANÇAS DE GO EM RELAÇÃO AO C

Embora ele não se parece superficialmente muito diferente de C ou C + +, a estrutura de Go é mais poderosa e oferece a facilidade de Python. A sintaxe e meio ambiente adotando padrões mais comuns em linguagens dinâmicas, Go inclui a mudança de C destinados a manter código conciso e legível. O programador não precisa especificar os tipos de expressões, semicolons no estreitol das linhas não são necessários. Funções podem retornar valores múltiplos, nomeado, e retornando a um resultado. Possuem uma maneira padrão de lidar com erros, depois de inicialmente omitindo exceções, a língua acrescentou o panic / recover mecanismo, mas ele serve apenas em raras circunstâncias.

As Estruturas complexas podem ser construídas durante a inicialização e as questões de ordenação entre os objetos inicializados, mesmo entre diferentes pacotes, são tratados de forma concorrente.

Sobre a coleta de lixo, uma das maiores fontes de contabilidade em programas de sistemas é o gerenciamento de memória. Nós sentimos que é fundamental para eliminar a sobrecarga do programador e os avanços na tecnologia de coleta de lixo nos últimos anos nos dão confiança de que podemos implementámos com baixo custo o suficiente e sem latência significativa. Grande parte da dificuldade de programação concorrente e multithreaded é o gerenciamento de memória, como os objetos são passadas entre threads torna se complicado para garantir que se tornem libertados em segurança. Coleta de lixo

VISITE UMA IGREJA EVANGELICA

Page 198: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

automática torna o código concorrente muito mais fácil de escrever. Claro, a implementação de coleta de lixo em um ambiente concorrente é em si um desafio, mas respeite-lo uma vez, e não em todos os programas de ajuda a todos. Estreitolmente, a simultaneidade de lado, a coleta de lixo faz com que as interfaces mais simples, pois não precisa especificar como a memória é gerenciada através deles.

Sobre o tema da performance, GO dá ao programador um controle considerável sobre layout de memória e alocação, muito mais do que é típico em linguagens de coleta de lixo. Um programador de cuidado pode reduzir a sobrecarga de coleta de lixo de forma dramática, usando bem o idioma.

Go é principalmente na família C (sintaxe básica), com a contribuição significativa da família Pascal / Modula / Oberon (declarações, pacotes), além de algumas ideias de linguagens inspiradas pela CSP de Tony Hoare, como Newsqueak e Limbo (simultaneidade). No entanto, é uma nova linguagem através da placa. Em todos os aspectos da linguagem foi projetada pensando sobre o que os programadores fazer e como fazer a programação, no mínimo, o tipo de programação que fazemos, mais eficaz, o que significa mais divertido.

Em primeiro lugar, a sintaxe deve é leve, sem muitas palavras-chave obrigatórias, repetição. Em segundo lugar, a linguagem foi projetada para ser fácil de analisar e pode ser analisado sem uma tabela de símbolos. Isso torna muito mais fácil construir ferramentas como depuradores, analisadores de dependência, plug-ins de IDE, e assim por diante, C e seus descendentes são notoriamente difícil a este respeito.

Programação de hoje envolve muito escrituração, repetição e trabalho de escritório. Como Dick Go tentativas de reduzir a quantidade de digitação, em ambos os sentidos da palavra. Ao longo de sua concepção, temos tentado reduzir a desordem e complexidade. Não há declarações para a frente e não arquivos de cabeçalho, tudo é declarado exatamente uma vez. A inicialização é expressivo, automático e fácil de usar. A sintaxe é limpo e leve em palavras-chave. Gagueira (foo.Foo*myFoo=new(foo.Foo)) é reduzida por simples derivação tipo usando o := declara reinicializar construto. E talvez o mais radical, não há hierarquia de tipos: tipos são apenas, eles não têm para anunciar seus relacionamentos.

As declarações são apenas para trás, se você está acostumado a C. Em C, a noção é que uma variável é declarada como uma expressão que denota o seu tipo, o que é uma boa ideia, mas o tipo de expressão e gramáticas não se misturam muito bem e os resultados podem ser confusos;

Go principalmente separa expressão e tipos de sintaxe e que simplifica e mantem as coisas claras. A Análise também é simplificada por ter uma gramática distinta para tipos;

Não há a aritmética de ponteiro, por motivo de segurança, pois sem a aritmética de ponteiro, é possível criar uma linguagem que nunca pode derivar um endereço ilegal que sucede de forma incorreta. Compilador e tecnologia de hardware têm avançado ao ponto onde um loop usando índices de array pode ser tão eficiente quanto um loop usando a aritmética de ponteiro. Além disso, a falta de aritmética de ponteiros pode simplificar a implementação do coletor de lixo.

Sem a aritmética de ponteiro, o valor de conveniência de pré e operadores de incremento posfixo sai e a sintaxe de expressão é simplificada e as questões confusas em torno de ordem de avaliação de + + e -- (considere f (i++) e p [i]=q [++i]) são eliminados. A simplificação é significativa.

Existem chaves, mas sem ponto e vírgula e não é possível colocar a chave de abertura na próxima linha. Go usa colchetes cinta para agrupamento comunicado, uma sintaxe familiar aos programadores que trabalharam com qualquer idioma na família C. Ponto e vírgula, no entanto, são para analisadores, não para as pessoas, e nós queríamos para eliminá-los, tanto quanto possível. Para atingir este objetivo, Go emprestado um truque de BCPL: as vírgulas que as declarações separadas estão na gramática formal, mas são injetadas automaticamente, sem visão antecipada, pelo léxico, no estreitol de qualquer palavra que poderia ser o fim de um comunicado. Isso funciona muito bem na prática, mas tem o efeito que ele força um estilo cinta. Por exemplo, a par de uma função de abertura não pode aparecer em uma linha por si só.

Algumas Grandes Empresas utilizadoras de Go

BBCBeachfront MídiaBitbucketCanonicalCloudFlareCloud FoundryFlipboardGitHub

Globo.comIntel AlemanhaMozillaMROfficeSpliceStatHatSteals.comStreetspotrStretchr

VISITE UMA IGREJA EVANGELICA

Page 199: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

TamberThomson Reuters EikonTinkerCadTorbitTumblr

TweetQureet UrlistVikiVividCortexZynga

Plataformas e arquiteturas

Os compiladores desenvolvidos para os seguintes sistemas operacionais mais populares do mundo (Linux, Windows e Mac Os) entre outros.

Os compiladores: gc e gccgo, trabalham em sistemas Unix-like. O compilador gc / runtime foi portado para Windows e está integrado na distribuição principal.

Go está disponível na fonte e em forma binária nessas plataformas amd64, 386, ARM.A portabilidade do Go-código entre Sistemas é excelente: basta copiar o código-fonte para o outro

Sistema e compilar.Os compiladores e linkers Go são escritos em C e produzir código nativo, de modo que um compilador

diferente é necessário para cada combinação de arquitetura (32 bits e 64 bits) e OS.O gccgo-compiler, é um compilador GNU mais tradicionalmente usado, que tem como alvo uma gama

muito ampla de processador de arquiteturas. Compilação é mais lento, mas o código nativo gerado é mais rápido. Este também oferece algumas interoperabilidades com C.

As extensões de arquivo e pacotes para código fonte Go é. go e arquivos C terminam em c e arquivos de montagem em s. Um programa executável em Windows é.exe.

A arquitetura Go-compilador permite compilação cruzada: você pode compilar em uma máquina (= o anfitrião), que tem outras características (sistema operacional, processador) do que a máquina de destino.

Instalando Go em um sistema Linux

Procure por “golang” na central de programas do ubuntu é o modo mais fácil de instalar, mas você pode compilar a partir do código fonte se quiser.

A ferramenta Go é escrito em C, então para o processo de construção que você precisa desses programas:

GCC, O padrão C bibliotecas libc6-dev, O gerador de analisador Bison, Go Gawk O editor de código.

2.7 O tempo de execução Go

Embora o compilador gera código executável nativo, esse código é executado dentro de um tempo de execução (o código dessa ferramenta está contida no tempo de execução do pacote). Este tempo de execução é um pouco comparável com as máquinas virtuais usados pelo Java e. NET. Ele é responsável pelo gerenciamento de alocação de memória e coleta de lixo, a movimentação de pilha, goroutines, canais, slices, mapas, reflexão e muito mais.

Coletor de lixo: Ter uma linguagem de coleta de lixo não significa que você pode ignorar as questões de alocação de memória: alocação e desalocação de memória também usa cpu-recursos. Arquivos executáveis são muito maiores em tamanho binário do que os arquivos de código fonte, este é precisamente porque o tempo de execução Go é incorporado em cada executável. Esta poderia ser uma desvantagem quando se tem para distribuir o executável para um grande número de máquinas. Mas, a implantação é muito mais fácil do que com Java ou Python, porque Go gera um binário estático e não são necessários outros arquivos. Não há nenhuma dependência circulares.

Mais Portabilidade dos programas para Windows com o MinGW

VISITE UMA IGREJA EVANGELICA

Page 200: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Um Go Makefile também pode ser usado no Windows usando MinGW (http:/ /www.mingw.org/). A fim de ser capaz de executar o conjunto de ferramentas Go (como gomake, gotest, etc.) do Windows-ambiente deve ser mais Unix-like. Isto pode ser feito através de MinGW, que ainda lhe dá a possibilidade de construção de Go no Windows.

Um ambiente companheiro limitado para trabalho Go-Makefiles em um ambiente Windows, incluindo MSYS pode ser encontrada em https:/ /bitbucket.org/akavel/gowin-env.

MinGW, uma contração de "minimalista GNU for Windows", é um ambiente de desenvolvimento minimalista para aplicações nativas do Microsoft Windows, que é necessário para rodar alguns aplicativos próprios do Linux no Windows.

MinGW fornece um conjunto de ferramentas Opensource de programação completa, que é adequado para o desenvolvimento de aplicações nativas MS-Windows, e que não depende de quaisquer 3-party C-Runtime DLLs. (Ele faz depender de uma série de DLLs fornecido pela própria Microsoft, como componentes do sistema operacional; mais notáveis entre estes é MSVCRT.DLL, a biblioteca de tempo de execução Microsoft C Além disso, os aplicativos segmentados deve ser fornecido com uma DLL apoio fio distribuído gratuitamente, fornecida como parte do próprio MinGW).Compiladores MinGW fornece acesso à funcionalidade de tempo de execução do Microsoft C e alguns tempos de execução específicos do idioma. MinGW, sendo minimalista, não faz, e nunca será, tentativa de fornecer um ambiente de execução POSIX para a implantação de aplicativos POSIX em MS-Windows. Se você quer a implantação de aplicativos POSIX nesta plataforma, por favor considere Cygwin em seu lugar.Principalmente destinado ao uso por desenvolvedores que trabalham na plataforma nativa MS-Windows, mas também está disponível para uso cross-hospedado, (ver nota abaixo - você pode precisar de seguir o " leia mais "link para vê-lo), MinGW inclui:

A porta do GNU Compiler Collection (GCC), incluindo C, C + +, Fortran e ADA; GNU Binutils para Windows (assembler, linker, gerente de arquivo) Um instalador de linha de comando (mingw-get) para MinGW e MSYS implantação em MS-Windows Um wrapper GUI (mingw-get-inst) para a instalação de linha de comando

MSYS, uma contração de "sistema mínimo", é um sistema de linha de comando intérprete Bourne Shell. Oferecido como uma alternativa para cmd.exe da Microsoft, isso proporciona um ambiente de uso geral de linha de comando, que é particularmente adequado para usar com MinGW, para portar de muitas aplicações Opensource para a plataforma MS-Windows; um garfo leve de Cygwin- 1.3, que inclui uma pequena seleção de ferramentas Unix, escolhido para facilitar esse objetivo.

Editores e Ambientes de Desenvolvimento Integrado

Destaque de sintaxe e outros Go-utilidades existem para os seguintes editores: Emacs, Vim, Xcode3, KD Kate, TextWrangler, BBEdit, mcedit, TextMate, textpad, Jedit, SciTE, Nano, Notepad + +, Geany, SlickEdit, SublimeText2.

Aqui segue uma discussão mais detalhada de LiteIDE e GoClipse.

Golang LiteIDE

A versão pode ser baixada no site: http:/ /code.google.com/p/golangide/)LiteIDE é um bom IDE leve, com uma arquitetura de plug-ins (baseado em QT, Kate e SciTE),

contendo todas as características necessárias para o desenvolvimento multi-plataforma Go confortável, com muito boa edição, de conclusão de código e suporte à depuração. Ele tem o conceito de um projeto Go, amarrado a um Makefile quando este está presente em seu diretório raiz. É possível trabalhar lado a lado com diferentes ambientes Go.

3.2.2. GoClipseA versão pode ser baixada no site: http:/ /code.google.com/p/goclipse/)Este é um plug-in para o bem conhecido para o ambiente Eclipse, um ambiente grande depende de

uma máquina virtual Java instalada, que pode usar grande parte da funcionalidade do Eclipse.

VISITE UMA IGREJA EVANGELICA

Page 201: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

3.3 depuradoresProgramação de aplicativo precisa de um bom suporte à depuração, e nesta área ainda muito trabalho

precisa ser feito. Um depurador (Oogle): suporte para gdb, o depurador GNU está sendo construída em Go gc linker (6l, 8l) pelo Google.

Formatando código: Go fmt ou gofmt

Os autores não queria discussões intermináveis sobre estilo de código para linguagem, discussões que, no passado, subiram para muitas linguagens de programação e que eram certamente de uma forma um desperdício de tempo de desenvolvimento precioso. Então eles fizeram uma ferramenta: gofmt.

Que impõe a oficial, formatação de código padrão e estilo no código-fonte Go. É uma ferramenta de reescrita nível de sintaxe, uma forma simples de refatoração: use gofmt em seu programa Go antes de compilar ou verificar. Embora não sem debate, o uso de gofmt e como consequência, a sintaxe da liberdade que você tem que desistir de certamente ter grandes vantagens em fazer código uniforme e melhor legível e, portanto, facilita a tarefa cognitiva de compreender Go-código estrangeiraa. A maioria dos editores tê-lo construído dentro para recuo de diferentes níveis no código não é rirárosa a regra, você pode personalizar.

desempenho do Go

De acordo com o Go-equipe e medido em programas de algoritmos simples, o desempenho é normalmente dentro de 10-20% dos C. Não há referências oficiais, mas as comparações experimentais regulares entre línguas mostram uma pista muito boa performance. Uma declaração mais realista é que Go é 20% mais lento do que C + +. Isso coloca os programas Go conservador duas vezes mais rápido e exige 70% menos memória quando comparado a um Java equivalente ou aplicação Scala. Em muitos casos essa diferença é Irrelevante, mas para uma empresa como a Google, com milhares de servidores potenciais melhorias de eficiência são certamente vale a pena o investimento.

Os atuais linguagens populares executadas em uma máquina virtuais: JVM para Java e Scala, NET CLR para C #, etc. Mesmo com as melhorias enormes em máquinas virtuais, JIT-compiladores e intérpretes de linguagem de script (Ruby, Python, Perl, Javascript) ninguém pode chegar perto de C e C + + para o desempenho.

Se Go é 20% mais lento do que C + +, que ainda é de 2 a 10 vezes mais rápido do que qualquer língua que não é de tipagem estática e compilada, e é muito mais eficiente de memória.

Alguns resultados de benchmarking:(1) Comparando Go e Python em aplicações de servidor web simples, medidos em transações / s:O pacote http Go nativa é 7-8 x mais rápido do que web.py, web.go ligeiramente menos eficaz com

uma proporção de 6-7 em comparação com web.py. O tornado assíncrona servidor / framework muito utilizado em ambientes web Python executa consideravelmente melhor do que web.py: Go Supera tornado apenas com um fator de 1,2 a 1,5.

(2) Vão é, em média, 25 x mais rápido do que o Python 3, utiliza 1/3 da memória, com o número de linhas de código quase igual ao dobro.

(3) O artirá de Robert Hundt comparando C + +, Java, Go, e Scala, e, a reação da equipe Go: algumas conclusões tendo em conta a aestreitoção do Go-time:

- Versões Scala e Go são significativamente mais compacto (menos linhas de código) do que o verboso C + + e Java

- Vai compila mais rápido do que outros, 5-6x comparando para Java e C + +, 10x em comparação com Scala

- Go tem o maior tamanho de binário (cada executável contém o tempo de execução)- Otimizado código Go é tão rápido como C + +, 2 a 3x mais rápido do que a versão Scala e 5 a 10

vezes mais rápido do que Java.- O seu consumo de memória também é muito semelhante ao de C + +, cerca de metade do que Scala

necessária, e foi quase 4x menos de Java.

Interação com outros idiomas.

Interagindo com C

VISITE UMA IGREJA EVANGELICA

Page 202: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

O programa CGO fornece o mecanismo para FFI-support (interface de função estrangeiraa) para permitir a chamada seguro de bibliotecas C do Código de Go:CGO substitui os normais Go-compiladores, ele gera arquivos Go e C que podem ser combinados em um único pacote Go. É uma boa prática para combinar as chamadas para C em um pacote separado.

Interagindo com C + +

SWIG (simplificado Wrapper and Interface Generator) apoio existe para chamar C + + e código C a partir de Go em Linux. Usando SWIG é um pouco mais complexo:

Escreva o arquivo de interface SWIG para a biblioteca para ser enrolado SWIG Irá gerar as funções C stub Estes podem, então, ser chamada usando a maquinaria cgo Os arquivos são automaticamente gerados

Unicode UTF-8

Unicode é um padrão que permite aos computadores representar e manipular, de forma consistente, texto de qualquer sistema de escrita existente. Seu sucesso em unificar conjuntos de caracteres levou a um uso amplo e predominante na internacionalização e localização de programas de computador. O padrão foi implementado em várias tecnologias recentes, incluindo XML, Java e sistemas operacionais modernos.

O Unicode possui o objetivo explícito de transcender as limitações de codificações de carácter tradicionais.

O armazenamento dos códigos Unicode no processamento de texto apresenta o desafio de a maioria dos programas de computador escritos no mundo ocidental utilizar somente codificações de 8 bits — 1 byte — (como o padrão ASCII), já que o suporte ao Unicode começou somente nos últimos anos. Similarmente, na representação de sistemas de escrita asiáticos, o modelo baseado em ASCII de caracteres de 2 bytes não pode mesmo em teoria codificar mais que 32 7688 caracteres e, na prática, as arquiteturas impõem limites ainda menores. Tais limites são insuficientes mesmo só tendo em conta as necessidade de acadêmicos da língua chinesa.

Por outro lado, a UTF-8 é uma codificação de muito usada, e que maximiza a compatibilidade com ASCII. Utiliza entre um e quatro bytes por código e, sendo compacta para o sistemas latino e compatível com ASCII nos códigos até 127, fornece um padrão de fato de codificação para a conversão de textos para o formato Unicode. É usada pelas mais recentes distribuições Linux como uma substituta para codificações legadas na manipulação de texto. A UTF-8 representa uma forma de otimizar o espaço alocado para textos Unicode. Considerando por exemplo um texto escrito em língua inglesa, percebe-se que raramente são utilizados caracteres fora do escopo do ASCII, isto é, os primeiros 127 códigos Unicode. Isso significa que se for utilizada uma codificação de largura fixa de 16 bits, o segundo byte de cada carácter muito provavelmente estará vazio, nulo, inutilizado. Para arquivos grandes a sobrecarga desse espaço inútil alocado passa a ser relevante. Tendo uma largura variada, o UTF-8 define que caracteres ASCII são representados com somente um byte. Além de otimizar o espaço alocado no caso de caracteres ASCII, isso garante a paridade entre ASCII e UTF-8, facilitando a tradução de texto ASCII legado para o Unicode. Uma propriedade adicional do UTF-8 diz respeito ao truncamento de cadeias de caracteres Unicode. Alguns códigos de processamento de cadeias de caracteres definem que um único byte nulo (0x00) representa o fim da cadeia.

O Unicode tornou-se o esquema predominante para o processamento interno de texto, e por vezes também para o armazenamento (apesar de muitos textos ainda estarem armazenados em codificações legadas).

O sistema mais conhecido nessa situação foi o Windows NT (e seus descendentes Windows 2000 e Windows XP). Os ambientes de bytecode das plataformas Java e.NET, o sistema operacional Mac OS X e o ambiente gráfico KDE também usam o UTF-16 para a representação interna.

Caracteres de identificador regra da Go devem ser letras ou dígitos, conforme definido pelo Unicode é simples de entender e de implementar, mas tem restrições. Combinando personagens são excluídos por design, por exemplo. Até que haja uma definição externa comum do que um identificador pode ser, além de uma definição de canonização de identificadores que garante nenhuma ambiguidade, parecia melhor manter combinando personagens fora da mistura. Assim, temos uma regra simples que pode ser expandida mais tarde, sem programas de quebra, uma que evita erros que certamente surgem a partir de uma regra

VISITE UMA IGREJA EVANGELICA

Page 203: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

que admite identificadores ambíguos.Em uma nota relacionada, uma vez que um identificador exportado deve começar com uma letra

maiúscula, identificadores criados a partir de "letras" em algumas línguas podem, por definição, não pode ser exportado. Por agora, a única solução é usar algo como X 日本語 , que é claramente insatisfatório; estamos considerando outras opções. A regra case para visibilidade não deve mudar no entanto, é um dos nossos recursos favoritos do Go.

Notação

A sintaxe é especificado usando estendida Backus-Naur Form (EBNF): Produção = production_name "=" [expressão] "." . Expressão = {Alternativa "|" Alternativa}. Alternativa = Term { } Term. Termo = production_name | símbolo ["..." símbolo] | Grupo | Opção | Repetição. Grupo = "(" Expressão ")". Opção = "[" Expressão"]". Repetição = "{" Expressão"}".

Produções são expressões construídas a partir de termos e os seguintes operadores, no aumento da precedência:

| Alternância ( ) Agrupamento [ ] Opção (0 ou 1 vezes) { } Repetição (0 a n vezes)

Blocos

Um bloco é uma sequência possivelmente vazio de declarações e instruções dentro correspondentes suportes de chave.

Block = "{" StatementList "}". StatementList = { Statement ";"}.Além de blocos explícitos no código-fonte, há blocos implícitas:

1. O bloco universo engloba tudo Go texto original.2. Cada pacote tem um bloco de pacote contendo todas Go texto de origem para esse pacote.3. Cada arquivo tem um bloco de arquivo que contém todas Go texto de origem no arquivo.4. Cada "for" , "if" , e "switch" declaração é considerado em seu próprio bloco implícito.5. Cada cláusula de um "switch" ou "select" Declaração age como um bloco implícito.Blocos ninho e influência de escopo.

Declarações e escopo

A declaração se liga um não-Nulo identificador para uma constante, tipo, variável, função, rótulo ou embalagem. Cada identificador de um programa devem ser declaradas. Nenhum identificador pode ser declarado duas vezes no mesmo bloco, e nenhum identificador pode ser declarado, tanto o arquivo e bloco de pacote.Go é escopo léxico usando blocos:

1. O escopo de um identificador predeclarado é o bloco universo.2. O escopo de um identificador que indica uma constante, tipo, variável ou função (mas não do

método) declarada no nível superior (fora de qualquer função) é o bloco de pacote.3. O escopo do nome do pacote de um pacote importado é o bloco do arquivo que contém a

declaração de importação de arquivos.4. O escopo de um identificador que indica um receptor método, parâmetro de função ou variável

VISITE UMA IGREJA EVANGELICA

Page 204: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

resultado é o corpo da função.5. O escopo de um identificador constante ou variável declarada dentro de uma função começa no

estreitol do ConstSpec ou VarSpec (ShortVarDecl para declarações de variáveis curtos) e termina no estreitol do bloco mais interno que contém.

6. O âmbito de um identificador do tipo declarado dentro de uma função começa no identificador no TypeSpec e termina no fim do bloco mais interna contendo.

Um identificador declarado em um bloco pode ser declarado novamente em um bloco interno. Enquanto o identificador da declaração interna está no escopo, denota a entidade declarada pela declaração interior.

A cláusula do pacote não é uma declaração, o nome do pacote não aparece em qualquer âmbito. Sua estreitolidade é identificar os arquivos que pertencem ao mesmo pacote e especificar o nome do pacote padrão para declarações de importação.

Voltando ao programa que vimos no início:

pacage maimimport "fmt"função main ( ) {var x string = "Olá Mundo!"fmt.Println (x)}Outra maneira de escrever este programa seria como este:

pacage maimimport "fmt"var x string = "Olá Mundo!"função main ( ) {fmt.Println (x)}

Observe que nos mudamos a variável fora da principal função. Isto significa que as outras funções podem acessar esta variável:

var x string = "Olá Mundo!"função main ( ) {fmt.Println (x)}função f ( ) {fmt.Println (x)}

O f função agora tem acesso ao x variável. Agora suponha que escreveu isto:

função main ( ) {var x string = "Olá Mundo!"fmt.Println (x)}função f ( ) {fmt.Println (x)}

Se você executar este programa, você verá um erro:

. \ Main.go: 11: undefined: x

O compilador está dizendo que o x variável dentro de o f função não existe. Só existe dentro do principal função. A variedade de lugares onde você usa x é chamado o âmbito da variável. Acordões para a especificação da linguagem "Go é lexicalmente escopo usando blocos ". Basicamente, isto significa que o variável existe dentro de chaves mais próximas { } (Um bloco), incluindo todas as chaves aninhadas (blocos), mas não fora deles. O escopo pode ser um pouco confuso no primeiro, como vemos mais

VISITE UMA IGREJA EVANGELICA

Page 205: Linguagem de Programação Go Google Apostila Livro Curso.docx

SITE OFICIAL: http://golang.org/

Exemplos Go que devem tornar-se mais clara.

Nomes de arquivo Palavras-chave-Identifiers

O código-fonte é armazenado em.go arquivos, esses nomes consistem em minúsculas-letras, como scanner.go Se o nome composto de várias partes, não são separadas por sublinhados _, como scanner_test.go

Os nomes de arquivo não pode conter espaços ou outros caracteres especiais.O arquivo de origem contém as linhas de código, que de comprimento não têm limite intrínseco.Quase todas as coisas em Go-código tem um nome ou um identificador. Como todas as línguas no C-

família, é sensível a maiúsculas. Identificadores válidos começar com uma letra (a letra é cada letra Unicode UTF-8 ou _), e seguido por 0 ou mais letras ou dígitos Unicode, como: X56, grupo1, _x23, i, ө ԑ 12

Não são identificadores válidos:1ab(Começa com dígito), caso (= palavra-chave no Go), a + b (operadores não são permitidos)O _ em si é um identificador especial, chamado de identificador em branco. Ele pode ser usado em

declarações ou atribuições de variáveis como qualquer outro identificador (e qualquer tipo pode ser atribuído a ele), mas o seu valor é descartado, para que ele não pode mais ser usado no código que se segue.

Às vezes é possível que as variáveis, tipos ou funções não têm nome, porque não é realmente necessário naquele momento no código e até mesmo aumenta a flexibilidade: estes são chamados anônimo.

Este é o conjunto de 25 palavras-chave ou palavras reservadas usadas em Go-código:

break else import struct case fallthrough interface switch chan for map type const func package var continue go range select default goto return defer if

Ele é mantido deliberadamente pequena para simplificar o código-análise, o primeiro passo no processo de compilação.

A chave não pode ser utilizado como um identificador.Além das palavras-chave GO tem um conjunto de 36 identificadores predeclarados: estes contêm os

nomes de tipos elementares e algumas funções internas básicas, todos estes serão explicados ainda mais nos próximos capítulos:

appendcopyint32printboolfalseint64printlnbytefloat32iotarealcapfloat64lenrecovercloseimag

makestringcomplexintnewtruecomplex64int8niluintcomplex128int16panicuint8uint16uint32uint64uintptr

VISITE UMA IGREJA EVANGELICA

Page 206: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Programas consistem de palavras-chave, constantes, variáveis, operadores, tipos e funções.

Os seguintes delimitadores são usados: parênteses ( ), colchetes [ ] e chaves { }.Os seguintes caracteres de pontuação.,,, E ...são utilizados.Código é estruturado em declarações.

Uma declaração não precisa terminar com um ponto e vírgula (como é imposta no C e família). O compilador Vai tem um modo de inserir automaticamente vírgulas no estreitol de declarações.

No entanto, se várias instruções são escritas em uma única linha (uma prática que não é incentivado por razões de legibilidade), eles devem ser separados por ponto e vírgula;

Personagens

Os seguintes termos são usados para designar classes específicas de caracteres Unicode:

letter unicode_letter | "_" .decimal_digit "0" ... "9" .octal_digit "0" ... "7" .hex_digit "0" ... "9" | "A" ... "F" | "a" ... "f" .

As seguintes sequências de caracteres representam operadores , delimitadores, e outros símbolos especiais:

+ & += &= && == != ( )- | -= |= || < <= [ ]* ^ *= ^= <- > >= { }/ << /= <<= ++ = := , ;% >> %= >>= – ! … . : &^ &^=

Pacotes, importação e visibilidade

Os pacotes são uma forma de estruturar código: um programa é construído como um "pacote" (muitas vezes abreviado como pkg), que podem utilizar as instalações de outros pacotes.

Cada go-arquivo pertence a um pacote (como uma biblioteca ou espaço de nomes em outras línguas).Muitos arquivos diferentes. Go pode pertencem a um único pacote, por isso o nome do arquivo e nome

do pacote não são geralmente os mesmos.O pacote para o qual o arquivo de código pertence deve ser indicado na primeira linha, por exemplo:

package main. Um executável autônomo pertence ao package main. Cada aplicação Go contém um pacote chamado principal.

Uma aplicação pode ser composta de pacotes diferentes, mas mesmo se você usar só package main, você não tem que encher todo o código em um arquivo grande: você pode fazer uma série de arquivos menores cada um com pacote principais como primeira linha de código. Se você compilar um arquivo de origem com um nome de pacote que não seja principal, como pack1, o arquivo objeto é armazenado em pack1.a; um nome de pacote é escrito em letras minúsculas.

Quando o identificador (de uma constante, variável, tipo, função, campo de struct ...) começa com uma letra maiúscula, como Grupo1, em seguida, o "objeto" com este identificador é visível no código fora do pacote (assim disponível para o cliente -programas, dos importadores "do pacote), diz a ser exportado (como Público em linguagens OO). Identificadores que começam com uma letra minúscula não são visíveis fora do pacote, mas eles são visíveis e utilizáveis nos todo o pacote (como privado).

(Letras maiúsculas pode vir de toda a gama Unicode, como o grego, não apenas letras ASCII são permitidos.)

Assim, a importação de um pacote dá apenas o acesso aos objetos exportados nesse pacote.Suponha que temos uma variável ou função chamada Thing (começa com T por isso é exportada) em

Page 207: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

um pack1 pacote, então quando pack1 é importado no pacote atual, coisa pode ser chamado com a notação de ponto habitual de OO-línguas : pack1.Thing (. pack1 A é necessário!)

Assim, os pacotes também servem como espaços de nomes e pode ajudar a evitar name-choques (nome-conflitos): variáveis com o mesmo nome em dois pacotes são diferenciados por seu nome do pacote, como:

pack1.Thing e pack2.Thing

Um pacote pode, se o considerar útil (para encurtar, conflitos de nome ...), também será dado um outro nome (um apelido), como: fm import "fmt". O alias é usado no código a seguir:

package mainimport fm “fmt” / / alias3func main( ) {fm.Println(“hello, world”)}

Observação:

Importação de um pacote que não é utilizado no resto do código é uma compilação de erros (por exemplo: importado e não utilizado: os). Isto segue a Go-lema: "nenhum código desnecessário! "

Declarações de nível de pacote e inicializações:Após a declaração de importação 0 ou mais constantes (const), variáveis (var) e tipos (tipo) podem ser

declarados, que são global (tem escopo do pacote) e são conhecidos em todas as funções no código (como c e v em gotemplate, e que é seguida por uma ou mais funções (funções).

Funções

A declaração da função mais simples tem o formato:

func functionName ( )

Entre os parênteses não obrigatórios ( ), um ou mais parâmetros (separados por,) pode ser dado como entrada para a função. Após o nome de cada variável de parâmetro deve vir seu tipo.

A função principal de partida é necessária (geralmente a primeira função), caso contrário o erro de compilação undefined: main.main ocorre. main não tem parâmetros e nenhum tipo de retorno (ao contrário do C-família), caso contrário, você recebe o erro de compilação: função principal não deve ter argumentos e nenhum resultado valores de retorno.

Quando o programa é executado, depois de inicializações a primeira função chamada (o ponto de entrada do aplicativo) será main.main ( ) (como em C). O programa sai-imediatamente e com sucesso, quando retorna main.main.

O código em funções (o corpo) é colocada entre chaves: { }

O primeiro {deve estar na mesma linha que a função de declaração: esta é imposta pelo compilador e gofmt (compilação de erros: erro de sintaxe: ponto e vírgula inesperado ou nova linha antes de {).

(Isto acontece porque o compilador produz então função principal ( ), o que é um erro.)

A última} é posicionado após a função do código da coluna abaixo função; para pequenos eventos é permitido que tudo está escrito em uma única linha, como por exemplo: func Soma (a, b int) {int voltar a + b}

A mesma regra aplica-se sempre que { } são usados (por exemplo: se, etc.)Assim, esquematicamente, uma função geral se parece com:

func functionName (parameter_list) (return_value_list) { ...

Page 208: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}

Onde parameter_list é da forma (param1 type1, param2 type2, …) e return_value_list é da forma (ret1 type1, ret2 type2, …)

Nomes de funções só começar com uma letra maiúscula quando a função tem que ser usado fora do pacote, em seguida, eles seguem PascalCasing, caso contrário, eles seguem camelCasing: cada novo wordin o nome começa com uma letra maiúscula.

A linha: fmt.Println (“hello, world”) chama a função println do fmt pacote, que imprime a string de parâmetro para o console, seguido por uma nova linha de caracteres \ n.

O mesmo resultado pode ser obtido com fmt.Print (“hello, world\n”)Estas funções de impressão e println também pode ser aplicado a variáveis, como em: fmt.Println (arr),

eles usam o formato de saída padrão para o arr variável.Impressão de uma cadeia ou uma variável pode ser feito ainda mais simples com a impressão e println

funções predefinidas: print ("ABC") ou println ("ABC"), ou (com uma variável i): System.out.println (i)Estas são apenas para ser usado na fase de depuração, quando a implantação de um programa de

substituí-los por seus parentes FMT.A execução de uma função é interrompido quando o fechamento} é atingido ou quando uma instrução

de retorno é encontrado, a execução do programa continua com a linha após a chamada da função.O programa sai normalmente com o código 0 (Programa encerrado com o código 0), um programa que

termina de forma anormal sai com outro código inteiro como 1, o que pode ser usado para testar a execução exitosa de ele programa a partir de um script.

Comentários

package mainimport “fmt” / / pacote para implementação formatado I / O.func main( ) {fmt.Printf(“Καλημέρα κόσμε; or こんにちは 世界\n”)}

Isso ilustra o caráter internacional, imprimindo Καλημέρα κόσμε; ou こんにちは世界  , e também os caracteres utilizados para indicar um comentário. Existem duas formas de comentários:

1. Comentários de linha começa com a sequência de caracteres / / e pare no fim da linha. Um comentário linha funciona como uma nova linha.

2. Comentários gerais começam com a sequência de caracteres / * e continuar através da sequência de caracteres * / . Um comentário geral que contém um ou mais quebras de linha funciona como uma nova linha, caso contrário, ele age como um espaço. Os comentários não fazem ninho.

Cada pacote deve ter um comentário pacote, um bloco de comentário imediatamente anterior à instrução do pacote, introduzindo o pacote e fornecer informações relevantes para a embalagem e sua funcionalidade como um todo. A embalagem pode ser repartido por vários ficheiros, mas o comentário precisa de estar em apenas um deles.

Exemplo:

/ / Super-homem pacote implementa métodos para salvar o mundo./ // / A experiência tem mostrado que um pequeno número de processos pode provar/ / Útil ao tentar salvar o mundo.

Quase todo tipo de nível superior, const, var e func, e, certamente, todos os nomes exportados em um programa deve ter um comentário. Este comentário (chamado um comentário doc) aparece na linha anterior, e para uma função Abcd deve começar com: "ABCD ...".

Pacote super-homem

Exemplo:

Page 209: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

/ / EnterOrbit provoca Superman voar em órbita baixa da Terra, uma posição/ / Que apresenta várias possibilidades de planeta salvação.func enterOrbit( ) error { ...}

Tipos

Variáveis (como constantes) contêm dados, e os dados podem ser de diferentes tipos de dados ou tipos para breve. A declaração de uma variável com var inicializa automaticamente para o valor de zero definido para seu tipo type.A define o conjunto de valores e o conjunto de operações que podem ocorrer nesses valores.

Tipos podem ser primária (ou primitiva), como int, float, bool, string ou estruturados (ou composta), como struct, variáveis, slices, maps, canais e interfaces, que apenas descrevem o comportamento de um tipo.

Um tipo estruturado que não tem valor real (ainda) tem o valor nulo, que também é o valor padrão para estes tipos (em Objective-C que também é chamado de zero, em Java, é nulo, em C e C + + é NULL ou 0).

Não há hierarquia de tipos. As funções também podem ser de um certo tipo, este é o tipo da variável que é retornado pela função. Este tipo é escrito após o nome da função e sua lista de parâmetros opcionais, como:

func FunctionName (a typea, b typeb) typeFunc

A variável var retornou de typeFunc aparece em algum lugar na função na declaração:

return var

A função pode retornar mais de uma variável, então os tipos de retorno são indicados separados por vírgula de e rodeado por ( ), como: func FunctionName (a TypeA, b TypeB) (t1 tipo1, tipo2 t2)

Exemplo: a função atoi : func atoi (s string) (i int, err erro)Então retorno assume a forma: var1, var2Retorno Isso é muitas vezes usado quando o sucesso (true / false) da execução de uma função ou o

mensagem de erro é devolvido juntamente com o valor de retorno (ver várias atribuições abaixo).Use a palavra-chave para a definição de tipo de seu próprio tipo. Então você provavelmente vai querer

definir um tipo struct (ver Capítulo 10), mas também é possível definir um alias para um tipo existente, como em:

type IZ int

E então nós podemos declarar variáveis como:var a IZ = 5Dizemos que um tem int como tipo subjacente, o que torna possível a conversão.Se você tiver mais de um tipo de definir, você pode usar o formulário de palavras-chave consignado,

como em:

type ( IZ int FZ float STR string)

Cada valor deve ter um tipo após compilação (o compilador deve ser capaz de inferir os tipos de todos os valores):Go é uma linguagem de tipagem estática.

Estrutura geral de um programa Go

Page 210: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

O programa a seguir compila mas não faz nada útil, mas demostra a estrutura preferencial para um programa Go. Esta estrutura não é necessário, o compilador não se importa se main ( ) ou as declarações de variáveis vêm por último, mas uma estrutura uniforme torna o código Go melhor leitura de cima para baixo.

Todas as estruturas serão explicados neste e nos próximos capítulos, mas as ideias gerais são os seguintes:

• Após a importação: declarar constantes, variáveis e os tipos• Em seguida, vem a função init ( ), se houver qualquer: é uma função especial que cada pacote pode

conter e que é executado em primeiro lugar.• Em seguida, vem a função main ( ) (somente no package main)• Em seguida vêm do resto das funções, os métodos nos primeiros tipos, ou as funções de modo que

eles são chamados de main ( ) em diante, ou os métodos e funções alfabeticamente se o número de funções é alta.

gotemplate.go:

package mainimport (“fmt”)const c = “C”var v int = 5type T struct{ }func init( ) { / / initialization of package}func main( ) {

var a int Func1( ) / / ... fmt.Println(a)

}func (t T) Method1( ) {

/ /...}func Func1( ) { / / exported function Func1

/ /...}

A ordem de execução (início do programa) de um aplicativo Go é a seguinte:(1) todos os pacotes no package main são importados na ordem indicada, em cada pacote:(2) se importa pacotes, (1) é chamado para este pacote (de forma recursiva) mas um certo pacote é

importado apenas uma vez(3), em seguida, para cada pacote (em ordem inversa) todas as constantes e variáveis são avaliadas, e

init ( ) se ele contém essa função.(4) por fim no package main o mesmo acontece, e, em seguida, main ( ) começa a executar.

Conversões

Se necessário e possível um valor pode ser convertido (elenco, coagido) em um valor de outro tipo. Go nunca é implícito para conversão, isso deve ser feito de forma explícita, com a sintaxe como uma chamada de função (um tipo é usado aqui como uma espécie de função): valueOfTypeB = typeB (valueOfTypeA)

Exemplos:a: = 5.0

Page 211: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

b: = int (a)

Mas isso só pode ter sucesso em alguns casos bem definidos, por exemplo, de um tipo mais restreito a um tipo mais amplo (por exemplo: int16 para int32).

Na conversão de um tipo mais amplo para um tipo mais restreito (por exemplo: int32 para Int16, ou float32 para int) perda de valor (truncagem) podem ocorrer. Quando a conversão é impossível e que o compilador detecta isso, um erro de compilação é dada, caso contrário, ocorre um erro de execução.

As variáveis com o mesmo tipo de base podem ser convertidos um no outro:

var a IZ = 5c := int(a)d := IZ(c)

Sobre a nomear as coisas em Go

Ter um código Limpo, legível e simples são um dos principais objetivos para o desenvolvimento Go. gofmt impõe o estilo de código. Os nomes das coisas em Go deve ser curto, conciso, evocativa. Nomes longos com tampas mistos e sublinhados que são muitas vezes vistos, por exemplo em Java ou código Python muitas vezes dificulta a legibilidade.

Os nomes não devem conter a indicação do pacote: a qualificação com o nome do pacote é suficiente. Um método ou função que retorna um objeto é apontado como um substantivo, não obter … é necessária.

Para alterar um objeto, use SetName. Se necessário, Go usa MixedCaps ou mixedCaps ao invés de escrever ressalta nomes multiword.

Constantes

A const constante contém dados imutáveis.Estes dados só podem ser do tipo boolean, number (integer, float ou complex) ou string.Ele é definido da seguinte forma:

const identifier [type] = value, por exemplo: const Pi = 3.14159

O especificador de tipo [tipo] é opcional, o compilador pode derivar implicitamente o tipo do valor.

Exemplo explícita digitação: const b string = "abc"Exemplo digitação implícita: const b = "abc"

Um valor derivado de uma constante sem tipo torna-se digitou quando ele é usado dentro de um contexto que requer um valor digitado (caso contrário formulada: uma constante sem tipo leva o tipo necessário para o seu contexto):

var n intf (n + 5) / / constante numérica sem tipo "5" torna-se do tipo int

Constantes devem ser avaliadas em tempo de compilação, um const pode ser definida como um cálculo, mas todos os valores necessários para o cálculo deve estar disponível em tempo de compilação.

Então, isso é ok: c1 const = 2/3

Este não é: const c2 = getNumber ( ) / / Dá o erro de compilação: getNumber ( ), utilizado como valor

Constantes numéricas não têm tamanho ou sinal, pode ser de alta precisão arbitrária e não fazer nenhum overflow:

const Ln2= 0.693147180559945309417232121458\

Page 212: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

176568075500134360255254120680009const Log2E= 1/Ln2 / / este é um recíproco preciso const Billion = 1e9 / / constante flutuanteconst hardEight = (1 << 100) >> 97 Como demonstrado \ pode ser utilizado como um carácter de continuação de uma forma constante.Em contraste com as variáveis numéricas de diferentes tipos, com constantes que você não tem que

se preocupar com conversões: são como números ideais.Constantes podem transbordar apenas quando eles são designados para uma variável numérica com

muito pouca precisão para representar o valor, isso resulta em um erro de compilação. Atribuição múltipla é permitida, como em:

const beef, two, c = “meat”, 2, “veg”const Monday, Tuesday, Wednesday, Thursday, Friday, Saturday = 1, 2, 3, 4, 5, 6

const (

Monday, Tuesday, Wednesday = 1, 2, 3 Thursday, Friday, Saturday = 4, 5, 6)

As constantes podem ser utilizados para as contagens:

const (Desconhecido = 0Feminino = 1Masculino = 2)

Desconhecido, Feminino, Masculino já estão aliases para 0, 1 e 2. Eles podem de fato ser usado para testar esses valores, como em um switch / case construct .

Em tais casos, o valor iota podem ser usadas para enumerar os valores:

const ( a = iota b = iota c = iota)

O primeiro uso do iota dá 0, sempre que iota é usado novamente em uma nova linha, o seu valor é incrementado por 1, de modo = 0, b = 1, um c = 2. Este pode ser abreviado para:

const ( a = iota b c)

iota também pode ser usado em uma expressão, como iota + 50. Um novo bloco de const ou declaração inicializa iota volta para 0.

Naturalmente, o valor de uma constante não pode alterar-se durante a execução do programa, pois isso é impedido por um erro do compilador: não é possível atribuir a valor, em que o valor é o valor da constante. Um exemplo do pacote de tempo: os nomes para os dias da semana:

const ( Sunday = iota Monday Tuesday Wednesday

Page 213: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Thursday Friday Saturday)

Você pode dar a enumeração um nome de tipo, como neste exemplo:

type Color intconst (

RED Color = iota / / 0 ORANGE / / 1

YELLOW / / 2 GREEN / / .. BLUE INDIRÁ VIOLET / / 6

)

Observação: Existe uma convenção para citar identificadores constantes com todas as letras maiúsculas, como: const INCHTOwCM = 2.54, o que melhora a legibilidade e pode ser usado, desde que ele não está em conflito com a Regra de visibilidade.

Variáveis

Vocês sabem que os computadores possuem CPU e memória, certo? A CPU (Unidade Central de Processamento) é responsável pelo controle e processamento dos cálculos matemáticos e das resoluções de expressões lógicas. Todavia, os dados que são usados num processamento precisam ser armazenados em algum lugar – este lugar é a memória principal. Ela funciona como um “armário” que guarda nossos pertences. Todavia, como um armário, não podemos simplesmente Go guardando nossos pertences sem nenhuma arrumação. Para isso, existem “caixas” na memória (posições de memória), que nos permitem organizar essas informações. Essas caixas, conceitualmente recebem nomes e são conhecidas como variáveis.

Toda variável necessita ser declarada, ou seja, reserva-se um local da memória informando que tipo de dados residirão ali. A forma geral para declarar uma variável usa em Go é a palavra-chave var:

var identifier type

Importante notar é que o tipo é escrito após o identificador da variável, ao contrário do que qualquer outra linguagem de programação. Por que os designers Go escolheu para esta convenção?

Primeiro ele remove uma certa ambiguidade que pode existir em declarações C, por exemplo, por escrito int* a, b;

Apenas um é um ponteiro e b não é. A fim de declará-los ambos os ponteiros, o asterisco deve ser repetido.

No entanto, em Go, ambos podem ser declarados ponteiros da seguinte forma: var a, b *intEm segundo lugar, lê bem da esquerda para a direita e assim é mais fácil de entender.

Alguns exemplos:

var a intvar b boolvar str string

Que também pode ser escrito como:

var ( a int b bool

Page 214: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

str string

)

Este formulário é utilizado, principalmente, para declarar variáveis globais.Quando uma variável é declarada contém automaticamente o padrão zero ou valor nulo para o seu

tipo: 0 para int, 0,0 para float, falsa para bool, string vazia ("") para a string, nil para ponteiro, o zero-ed struct, etc. :

Toda a memória em Go é inicializado.A nomeação de identificadores para variáveis segue as regras camelCasing (começar com uma

pequena carta, a cada nova parte da palavra começa com uma letra maiúscula), como: numShips, startDate Mas se a variável tem de ser exportada, deve começar com um capital carta.

Uma variável (constante, o tipo de função) é conhecida apenas num determinado intervalo de programa, chamado o âmbito. Variáveis etc. declarada fora de qualquer função (em outras palavras, a nível superior) têm escopo global (ou pacote): eles são visíveis e disponíveis em todos os arquivos de origem do pacote.

Variáveis declaradas em uma função tem escopo local: eles só são conhecidos nessa função, o mesmo vale para os parâmetros e voltar-variáveis. No decorrer do livro vamos encontrar construções de controle, como se, e para, uma variável definida dentro de uma tal construção só é conhecido dentro desse construto (construção de escopo). Principalmente você pode pensar em um âmbito que o bloco de código (cercado por { }) em que a variável é declarada.

Embora identificadores têm de ser únicos, um identificador declarado em um bloco pode ser declarado novamente em um bloco interno: neste bloco (mas só lá) a variável redeclarado tem prioridade e sombras a variável externa com o mesmo nome, se cuidados utilizado deve ser tomado para evitar erros sutis.

Variáveis podem obter o seu valor (que é chamado de atribuição e usa o operador de atribuição =) em tempo de compilação, mas, naturalmente, um valor também pode ser calculado ou alterados durante a execução.

Exemplos:

a = 15b = false

Em geral, uma variável b só pode ser atribuído a uma variável como um em que a = b, quando a e b são do mesmo tipo. Declaração e atribuição (inicialização) pode, naturalmente, ser combinadas, no formato geral:

Exemplos:var identifier [type] = valuevar a int = 15var i = 5var b bool = falsevar str string = "Go diz Olá para o mundo!"

Mas o Go-compilador é inteligente o suficiente para obter o tipo de uma variável a partir de seu valor (de forma dinâmica, também chamada de tipo automático inferência, um pouco como nas linguagens de script Python e Ruby, mas isso acontece em tempo de execução), então as seguintes formas (omitindo o tipo) também estão corretas:

var a = 15var b = false var str = "Go diz Olá para o mundo!"

ou

var ( a = 15 b = false str = “Go says hello to the world!” numShips = 50

city string

Page 215: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

)

Ele ainda pode ser útil incluir o tipo de informação no caso em que você deseja que a variável a ser digitado algo diferente do que seria se inferir, como em: var n int64 = 2

No entanto uma expressão como uma var não é correto, porque o compilador não tem nenhuma pista sobre o tipo de um arquivo. Variáveis também podem ser expressões computadas em tempo de execução, tais como:

var (HOME = os.getenv ("HOME")USER = os.getenv ("USER")GOROOT = os.getenv ("GOROOT"))

A sintaxe var é usado principalmente em um nível pacote global, em funções que ele é substituído pela sintaxe declaração curta é : =

Aqui está um exemplo de um programa que mostra o sistema operacional em que ele é executado. Ele tem uma variável local string ficando o seu valor, chamando a função getenv (que é usado para obter ambiente de variáveis) a partir do pacote-os.

package mainimport ( “fmt” “os”)

func main( ) { var goos string = os.Getenv(“GOOS”) fmt.Printf(“The operating system is: %s\n”, goos) path := os.Getenv(“PATH”) fmt.Printf(“Path is %s\n”, path)}

A saída pode ser, por exemplo: O sistema operacional é: Windows ou Linux A operação, seguido pelo o conteúdo da variável de caminho. Aqui Printf é usado para formatar a saída de.

Tipos de valor e tipos de referência

Memória em um computador é usado em programas como um enorme número de caixas (que é como vamos chamar-lhes), chamado palavras. Todas as palavras têm o mesmo comprimento de 32 bits (4 bytes) ou 64 bits (8 bytes), de acordo com o processador e sistema operacional, todas as palavras são identificados pelo seu endereço de memória (representado como um número hexadecimal).

Todas as variáveis de tipos elementares (primitivas), como int, float, bool, string, ...são tipos de valor, eles apontam diretamente para o seu valor contido na memória:

O endereço de memória da palavra, onde a variável i é armazenado é dado por & i, por exemplo, isso pode ser 0xf840000040. Variáveis do tipo de valor são cointained na memória stock.

O valor real do endereço será diferente de uma máquina para outra e mesmo em diferentes execuções do mesmo programa que cada máquina pode ter uma disposição diferente e de memória, e também a localização onde é atribuído poderia ser diferente.

Dados mais complexo que geralmente necessita de várias palavras são tratadas como tipos de referência.

A variável de tipo de referência R1 contém o endereço (um número) da posição de memória em que o valor de r1 é armazenada (ou, pelo menos, a primeira palavra do mesmo).

Este endereço que é chamado um ponteiro também está contido em uma palavra.As palavras diferentes pontos de um tipo de referência ao poderiam ser endereços sequenciais de

Page 216: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

memória (o layout de memória está a ser dito de forma contígua), que é o armazenamento mais eficiente para a computação, ou as palavras poderiam ser espalhados ao redor, cada um apontando para o outro.

Ao atribuir r2 = r1, apenas a referência (endereço) é copiada.Se o valor de r1 é modificado, todas as referências de que o valor (como R1 e R2), em seguida,

apontam para o conteúdo modificado.Os ponteiros de Go são tipos de referência, bem como slices, maps e canais. As variáveis que são

mencionados estão armazenados no montão, o qual é recolhido o lixo, e que é um espaço de memória muito maior do que a pilha.

Impressão

A função printf é visível fora do pacote fmt porque começa com um P, e é usado para imprimir a saída para o console. Ele geralmente usa um formato de string como seu primeiro argumento:

func Printf(format string, list of variables to be printed)

Na Listagem 4.5 a cadeia de formato foi: "O sistema operacional é:% s \ n "

Este formato de sequência pode conter um ou mais especificadores de formato-% .., onde .. Indica o tipo do valor a ser introduzido, por exemplo, % s representa um valor de cadeia. % V é o especificador de formato padrão geral.

O valor (s) vêm na mesma ordem das variáveis resumiu após a vírgula, e elas são separadas por vírgula de, se houver mais do que 1.Estes marcadores de posição% preveem um controle muito estreito sobre a formatação.

O fmt.Sprintf função se comporta exatamente da mesma maneira como printf, mas simplesmente retorna a string formatada: por isso esta é a maneira de fazer strings contendo os valores das variáveis em seus programas.

As funções fmt.Print e fmt.Println executar a formatação automática de seus argumentos, usando o formato de especificador % v, acrescentando espaços entre argumentos e esta última uma nova linha no estreitol. Então fmt.Print (“Hello:”, 23) produz como saída: “Hello:”, 23

formulário curto com o operador: = atribuição

Com o tipo omitido, a palavra-chave var nas últimas declarações do é bem supérfluo, para que possamos escrever em Go: a: = 50 ou b: = false

Os tipos de a e b (int e bool) Novamente são inferidos pelo compilador.Esta é a forma preferida, mas apenas pode ser utilizado dentro de funções, não no âmbito do pacote :=

operador efetivamente faz uma nova variável, que também é chamado de declaração de inicializar.Observação: Se depois de as linhas acima no mesmo bloco de código nós declaramos a: = 20, isso

não é permitido: o compilador dá o erro "sem novas variáveis no lado esquerdo :=", no entanto a = 20 é ok, porque então o mesmo variável só recebe um novo valor.

Uma variável de a é usado, mas não declarada, dá um erro do compilador: undefined: aDeclarando uma variável local, mas não usá-lo, é um erro do compilador, como variável a da seguinte:

func main( ) { var a string = “abc” fmt.Println(“hello, world”)

}

Gue dá o erro: a declared and not used

Também a definição do valor de um não é suficiente, o valor deve ser lido, a fim de contar como um uso, de modo fmt.

Println(“hello, world”, a) remove o erro.

Page 217: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

No entanto, para as variáveis globais isso é permitido. Outras formas de encurtamento convenientes são:

Várias declarações de variáveis do mesmo tipo em uma única linha, como: var a, b, c intVárias atribuições de variáveis em uma única linha, como: a, b, c = 5, 7, "abc"Isso pressupõe que as variáveis a, b e c, onde já declarados, se não: a, b, c: = 5, 7, "abc"

Os valores a partir do lado direito são atribuídos às variáveis sobre o lado esquerdo, na mesma ordem, de modo a tem o valor de 5, b tem o valor de 7, c tem o valor "ABC".

Isso é chamado de atribuição paralela ou simultânea.Com duas variáveis que pode ser utilizada para realizar uma permuta de valores: a, b = b, a(Isto elimina a necessidade de fazer uma função swap em Go)O identificador branco _ também pode ser utilizado para deitar fora os valores, como o valor de 5: _,b = 5, 7_ Está em virár uma variável somente gravação, você não pode pedir para o seu valor. Ela existe

porque uma variável declarada em Go também deve ser utilizado, e às vezes você não precisa usar todos os valores de retorno de uma função.

A atribuição múltipla também é usado quando uma função retorna mais de um valor, como aqui, onde val e um err erro são retornados de Func1: val, err = Func1(var1)

funções init

Além de declaração global com a inicialização, variáveis também pode ser inicializado em uma init ( )-function.

Esta é uma função especial com nome init( ), que não pode ser chamado, mas é executado automaticamente antes da função main( ) no package main ou no início da importação do pacote que o contém.

Cada arquivo de origem pode conter apenas 1 init ( ) de funções. A inicialização é sempre único-threaded e garantias de dependência de pacotes para a execução correta.

Um uso possível é verificar ou reparar exatidão do estado do programa antes do início da execução real.

package transimport “math”var Pi float64func init( ) {

Pi = 4 * math.Atan(1) / / init( ) function computes Pi}

Na sua init ( ) o Pi variável é inicializada por cálculo.

O próximo programa importa o pacote trans (que está no mesmo diretório) e usa Pi:

package mainimport ( “fmt” “./trans”)var twoPi = 2 * trans.Pifunc main( ) { fmt.Printf(“2*Pi = %g\n”, twoPi) / / 2*Pi = 6.283185307179586}

Uma função init( ) também é frequentemente usado quando (por exemplo, para um aplicativo de servidor) um backend( ) goroutine é necessária desde o início da aplicação, como em:

func init( ) { / / setup preparations go backend( )}

Page 218: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

O QUE É UM TIPO

Ao armazenarmos variáveis na memória do computador, precisamos dizer que tipo elas são, para que seja reservado o espaço adequado, além de ser dado o trabalho correto a elas. Começaremos com exemplos clássicos na computação para explicar o que é um tipo:

TIPO INTEIRO: qualquer número inteiro, negativo, nulo ou positivo.Ex.: -15, 0, 101

TIPO REAL: qualquer número real, negativo, nulo ou positivo. Ex.: -1, -0.5, 0, 5, 9.5

TIPO LÓGICO OU BOOLEANO: conjunto de valores (FALSO ou VERDADEIROO)

Tipos e operadores elementares em Go

Em Go valores são combinados em conjunto com os operadores em expressões, que são também os valores de um determinado tipo.

Cada tipo tem seu próprio conjunto definido de operadores, que pode trabalhar com valores desse tipo. Se um operador é usado para um tipo para o qual ele não está definida, ocorre um erro do compilador.

Um operador unário trabalha em um valor (postfix), um operador binário funciona em dois valores ou operandos (infix).

Os dois valores para um operador binário deve ser do mesmo tipo. Go não converter implicitamente o tipo de um valor, se necessário isso deve ser feito por uma conversão explícita: Go se fortemente typed.There há sobrecarga de operador como em C e Java. Uma expressão é, por padrão, avaliado a partir da esquerda para a direita.

Há uma precedência built-in entre os operadores nos dizendo qual o operador em uma expressão tem a maior prioridade, e por isso é executado pela primeira vez. Mas o uso de parênteses ( ) em torno de expressão (s) podem alterar esta ordem: uma expressão dentro de ( ) é executado sempre em primeiro lugar.

Tipo bool booleano

Um tipo boolean representa o conjunto de valores de verdade booleanos denotados pelas constantes predeclaradas true e false. O tipo boolean predeclarado é bool.

Em qualquer comparação, o primeiro operando deve ser atribuível ao tipo do segundo operando, ou vice-versa.Os operadores de igualdade == e != aplicar a operandos que são comparáveis. Os operadores de ordenação < , <= , > , e >= aplica a operandos que são ordenados. Estes termos e os resultados das comparações são definidos da seguinte forma:

Os valores booleanos são comparáveis. Dois valores booleanos são iguais se eles são ou ambos true ou ambos false.

Os valores inteiros são comparáveis e ordenada, da maneira usual. Valores de ponto flutuante são comparáveis e ordenada, como definido pelo padrão IEEE-754. Complex valores são comparáveis. Dois valores complexos u e v são iguais se os dois real(u) ==

real(v) e imag(u) == imag(v) . String valores são comparáveis e ordenada, léxico byte-wise. Valores de ponteiro são comparáveis. Dois valores de ponteiro são iguais se eles apontam para a

mesma variável, ou se ambos têm valor nil . Os apontadores para distintas de tamanho zero variáveis podem ou não ser iguais.

Canal valores são comparáveis. Dois valores de canal são iguais se eles foram criados pela mesma

Page 219: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

chamada para make ou se ambos têm um valor nil . Valores de interface são comparáveis. Dois valores de interface são iguais se eles têm idênticas

tipos dinâmicos e valores dinâmicos iguais ou se ambos têm um valor nil . Um valor x do tipo não-interface de X e um valor de t de tipo de interface T são comparáveis quando

os valores do tipo X são comparáveis e X implementa T. Eles são iguais, se t 's tipo dinâmico é idêntico ao X e t 'valor dinâmico s é igual a x.

Struct valores são comparáveis, se todos os seus campos são comparáveis. Dois valores de struct são iguais se os seus não-correspondentes em branco os campos são iguais.

Valores da array são comparáveis se os valores do tipo do elemento da array são comparáveis. Dois valores de array são iguais se seus elementos correspondentes são iguais.

Um exemplo: var aVar = 10 aVar != 5 resultado verdadeiroo aVar != 10 resultado falso

Os valores possíveis deste tipo são constantes predefinidas verdadeiroas e falsas.Dois valores de um certo tipo podem ser comparados uns com os outros com os operadores

relacionais e ==! = Produzir um valor booleano:Operador de igualdade:==Isto dá verdadeiroo se os valores de ambos os lados são os mesmos (valores), caso contrário. Isto

supõe que eles sejam do mesmo tipo.Exemplo:var Avar = 10Avar == 5 falsoAvar == 10 verdade

Não-igual operador:! =Isto dá verdadeiroo se os valores de ambos os lados são diferentes (valores), caso contrário.Exemplo:var Avar = 10Avar! = 5 verdadeAvar! = 10 falsa

Go é muito rirároso sobre os valores que podem ser comparados: eles têm que ser do mesmo tipo, ou se eles são interfaces que deve implementar o mesmo tipo de interface. Se um deles é uma constante, que deve ser de um tipo compatível com o outro. Se estas condições não forem satisfeitas, um dos valores foi o primeiro a ser convertido para o tipo do outro.

Constantes booleanas e variáveis também podem ser combinados com operadores lógicos (e não, e, ou) para produzir um valor booleano. Tal assertion lógica não é a Go-declaração completa em si mesma.

É verdade, se qualquer um dos operandos é verdade, ele só dá falso se ambos os operandos são falsas.

O && e | | operadores se comportam de uma forma de atalho: quando o valor do lado esquerdo, é conhecido e é suficiente para deduzir o valor da expressão inteira (com falsa e verdadeiroa com && | |), em seguida, o lado direito não é mais calculado. Por essa razão: se uma das expressões envolve um cálculo longlasting, colocar essa expressão no lado direito.

Como em todas as expressões, ( ) pode ser usado para combinar os valores e influenciar o resultado.Em formato de string % t é usado como um especificador de formato para booleanos.Os valores booleanos são mais frequentemente utilizados (como valores ou combinado com os seus

operadores) para testar as condições de se-, para-se mudar-afirmações.A convenção de nomenclatura útil para valores booleanos e funções importantes é deixar o nome

começar com é ou, como IsSorted, isFound, isFinished, isVisible, então declarações if-código lê como uma sentença normal, por exemplo: unicode.IsDigit (ch).

Booleanos e Operadores de comparação.

Page 220: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

!b Lógico NÃO operador; falso se expressão booleana b é verdadeirooa || b Curto-circuito operador lógico OR; verdadeiroo se qualquer expressão booleana um ou b é verdadeiroa a && b Curto-circuito operador lógico AND; verdadeiroo se tanto Boolean expressões uma e b são verdadeiroasx < y verdadeiroo se a expressão x é menor do que a expressão yx <= y verdadeiroo se a expressão x é menor ou igual a Y expressãox == y verdadeiroo se a expressão x é igual a expressão yx != y verdadeiroo se a expressão x não é igual a expressão yx >= y verdadeiroo se a expressão x é superior ou igual à expressão y x > y verdadeiroo se a expressão x é maior do que a expressão y

Tipos numéricos

Um tipo determina o conjunto de valores e operações específicas para valores desse tipo. Tipos podem ser nomeado ou não. Tipos nomeados são especificadas por um (possivelmente qualificado) digite o nome, tipos anônimos são especificados usando um tipo literal, que compõe um novo tipo de tipos existentes.

Type = TypeName | TypeLit | "(" Type ")" .TypeName = identifier | QualifiedIdent .TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType | SliceType | MapType | ChannelType .

Go oferece 11 tipos inteiros separados, cinco assinado e cinco não assinado , além de um in-Type Teger para armazenar ponteiros. Go permite o uso de byte como um sinônimo para o não assinado uint8 tipo , e incentiva o uso de rune como um sinônimo para o tipo int32 quando trabalhar com caracteres individuais de código Unicode ). Não há hierarquia de tipo, para tornar a execução e compilação mais rapida e o códigos mais limpo. Go inteiros suportar todas as operações aritméticas, além disso, apoiar todas as operações aritméticas e bit a bit. Todas essas operações têm os comportamentos padrão esperado .Um tipo numérico representa conjuntos de valores inteiros ou de ponto flutuante. Os tipos numéricos independentes de arquitetura predeclarada são:

byte é o sinônimo para uint8 uint8 o conjunto de todos os inteiros de 8 bits sem sinal (0 a 255) uint16 o conjunto de todos os inteiros de 16 bits sem sinal (de 0 a 65535) uint32 o conjunto de todos os inteiros de 32 bits sem sinal (de 0 a 4294967295) uint64 o conjunto de todos os inteiros de 64 bits sem sinal (0-18446744073709551615) uintptr é um inteiro sem sinal capaz de armazenar um valor de ponteiro (avançado) rune é o sinônimo para int32 int8 o conjunto de todos os inteiros de 8 bits assinados (-128 a 127) int16 o conjunto de todos os inteiros de 16 bits assinados (-32768 a 32767) int32 o conjunto de todos os inteiros de 32 bits assinados (-2147483648 a 2147483647) int64 o conjunto de todos os inteiros de 64 bits assinados (-9223372036854775808 a

9223372036854775807)

Float32 o conjunto de todos os números de 32-bit de ponto flutuante IEEE-754 Float64 o conjunto de todos os números de 64-bit de ponto flutuante IEEE-754 complex64 o conjunto de todos os números complexos, com partes float32 reais e imaginários

complex128 o conjunto de todos os números complexos, com partes Float64 reais e imaginários

int é o tipo inteiro que oferece as velocidades de processamento mais rápido.O apoio da Go para inteiros de 64 bits faz com que seja realisticamente possível a utilização em escala inteiros para cálculos precisos em alguns contextos. Go tem arquitetura tipos dependentes, como int,uint, UIntPtr.

Eles têm o comprimento adequado para a máquina na qual o programa é executado:

Page 221: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Um int é o tipo assinado padrão: leva de 32 bits (4 bytes) em uma máquina de 32 bits e 64 bits (8 bytes) em uma máquina de 64 bits, o mesmo vale para o uint não assinado.Números inteiros - como sua contraparte matemática - são números sem um componente decimal. (..., -3, -2, -1, 0, 1, ...) Ao contrário do sistema decimal base 10 que usamos para representar números, os computadores utilizam uma base-2 sistemas binários.Um inteiro literal é uma sequência de dígitos que representam uma constante inteira. Um prefixo opcional define uma base não decimal: 0 para octal, 0x ou 0X para hexadecimal. Em literais hexadecimais, letras af e AF representam valores de 10 a 15.int_lit = decimal_lit | octal_lit | hex_lit .decimal_lit = ( "1" ... "9" ) { decimal_digit } .octal_lit = "0" { octal_digit } .hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } .

42 0600 0xBadFace 170141183460469231731687303715884105727

O valor inicial (default) para inteiros é 0, e para carros alegóricos este é 0.0 A float32 é confiável precisão de cerca de 7 casas decimais, um float64 para cerca de 15 casas decimais. Devido ao fato de que a precisão perfeita não é possível para flutuadores, comparando-os com == ou = deve ser feita com muito cuidado, e se necessário um teste sobre a diferença é menor do que um número muito pequeno (o limite de precisão) deve ser feita.

Use float64 sempre que possível, porque todas as funções do pacote de matemática esperar que tipo.Os números podem ser denotado em notação octal com um prefixo de 0 (como 077), hexadecimal com

o prefixo 0x (como 0xFF) ou a notação científica com e, que representa a potência de 10 (por exemplo: 1e3 = 1000 ou 6.022e23 = 6,022 x 1023).

Você pode fazer um número como este: a : = Uint64 (0) que é, de fato, a conversão de tipo a uint64

Porque Go é fortemente tipado, a mistura de tipos não é permitido, como no seguinte programa. Mas constantes são considerados não tipificado, a este respeito, por isso, com constantes de mistura é permitida.

package mainfunc main( ) { var a int var b int32 a = 15 b = a + a / / compiler error b = b + 5 / / ok: 5 is a constant}

O erro do compilador é: não pode usar a + um (tipo int) como tipo int32 em atribuiçãoDa mesma forma um int16 não pode ser atribuído a um int32, não há correlação implícita, deve-se

fazer a conversão.

package mainimport “fmt”func main( ) { var n int16 = 34

var m int32/ / Erro do compilador: não pode usar n (tipo int16) como tipo int32 em atribuição

/ /m = n m = int32(n)

fmt.Printf(“32 bit int is: % d \ n ", m)fmt.Printf(“16 bit int is: % d \ n ", n)

}/ / A saída é:

Page 222: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

32 bit int is: 3416 bit int is: 34

Especificadores de formato:

Em formato de strings% d é usado como um formato para especificador inteiros (% x% ou X pode ser usado para uma representação hexadecimal), g% é utilizado para tipos float (% f dá um ponto flutuante, % e dá uma notação científica), % 0ND mostra um inteiro com n dígitos, e levando 0 é necessário.

% n.mg representa o número com m dígitos após o sinal decimal, e n, antes disso, em vez de g também e f pode ser usado, por exemplo: o% 5.2e formatação do valor 3,4 dá 3,40 E +00

Conversões de valores numéricos:Em uma conversão como a32bitInt = int32 (a32Float) truncamento da parte decimal ocorre. Em geral a

informação é perdida durante a conversão para um tipo menor, portanto, a fim de evitar a perda de precisão sempre converter para o tipo numérico maior. Ou você pode escrever funções adequadas para realizar conversões de downsizing seguros, como o seguinte para converter um int para um uint8:

func Uint8FromInt (n int) (uint8, error) { if 0 <= n && n <= {math.MaxUint8 / / Conversão é segura return uint8 (n), nil }return 0, fmt.Errorf ("% d está fora do intervalo de uint8", n)}

Ou para seguro converter de um float64 para um int:

func IntFromFloat64(x float64) int { if math.MinInt32 <= x && x <= math.MaxInt32 { / / x está no intervalo inteiro whole, fraction := math.Modf(x)

if fraction >= 0.5 { whole++

} return int(whole) } panic(fmt.Sprintf(“%g is out of the int32 range”, x))}

No caso em que x não sentar no intervalo inteiro, o programa pára com uma mensagem de panic.Pergunta 4.1: Você int e int64 do mesmo tipo?

Para números complexos, temos os seguintes tipos:complex64 (Com uma parte de 32 bits reais e imaginários)complex128 (com uma parte de 64 bits reais e imaginários)Um número complexo é escrito na forma: re + imi, onde re é a parte real, e im é a parte imaginária e i é

a √ -1.Exemplo:

var c1 complex64 = 5 + 10ifmt.Printf (“The value is: %v”, c1)/ / Isso vai imprimir: 5 + 10i

Se re e im são do tipo float32, uma variável do tipo c complex64 pode ser feita com o complexo de função:

c = complex (re, im)As funções real (c) e imag (c) dar a parte real e imaginária, respectivamente.

Em formato de strings % v o especificador de formato padrão pode ser usado para números complexos, caso contrário usar% f para ambas as partes constituintes.

Os números complexos suportar todas as operações aritméticas normais como outros números. Você só pode comparar com == e !=, Mas mais uma vez estar ciente de precisão. O cmath pacote contém funções comuns para operar com números complexos. Quando restrições de memória não estão muito apertadas, use tipo complex128 porque todas as funções cmath usá-lo.

Page 223: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Números de ponto flutuante são números que contêm um componente decimal (números reais). Sua representação real em um computador é bastante complicado:

1. Números de ponto flutuante são inexatos. Ocasionalmente não é possível representar um número.2. Como inteiros números de ponto flutuante tem um certo tamanho Tain (32 bits ou 64 bits). Utilizando

um tamanho maior número de ponto flutuante aumenta é precisão.3. Em adição aos números existem vários outros valores que podem ser representados: "não é um

números “(NaN, Para coisas como 0/0) E positivo e infinito negativo. (+ ∞ e - ∞) Go tem dois tipos de ponto flutuante:

float32 e float64 (Também muitas vezes referida como precisão simples e dupla precisão, respectivamente), bem como dois tipos adicionais para representar números complexos (números com partes imaginárias):

complex64 e complex128.Um ponto flutuante literal é uma representação decimal de uma constante de ponto flutuante. Ele tem

uma parte inteira, um ponto decimal, uma parte fracionária, e uma parte expoente. O inteiro e parte fracionária compreendem dígitos decimais, a parte expoente é um e ou E seguido de um expoente decimal opcionalmente assinado. Um dos à parte inteira ou a parte fracionária pode ser elidida, uma do ponto decimal ou expoente pode ser elidida.

float_lit = decimals "." [ decimals ] [ exponent ] |decimals exponent |"." decimals [ exponent ] .decimals = decimal_digit { decimal_digit } .exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .

0. 72.40 072,40 / / == 72.40 2,71828 1.e 0 6.67428e-11 1E6 .25 0,12345 E +5

Um literal imaginário é uma representação decimal da parte imaginária de um complexo constante. Ele consiste de um literal de ponto flutuante inteiro ou decimal seguido pela letra minúscula i.imaginary_lit = (decimals | float_lit) "i" . 0i 011i / / == 11i 0.I 2.71828i 1.e 0 i 6.67428e-11i 1E6i 0,25 i 0,12345 E +5 i

Literais Rune

A rune literal representa uma constante rune, um valor inteiro que identifica um ponto de código Unicode. Um literal rune é expresso como um ou mais caracteres entre aspas simples. Dentro das citações, qualquer personagem pode aparecer exceto aspas simples e de nova linha. Um único caractere citado representa o valor Unicode do próprio personagem, enquanto sequências multicaráter começa com uma barra invertida valores codificar em vários formatos.

A forma mais simples representa o caráter único dentro das aspas, uma vez Go texto de origem é caracteres Unicode codificados em UTF8, vários bytes codificado em UTF8 pode representar um único valor inteiro. Por exemplo, o literal ' a ' possui um único byte que representa um literal a, Unicode U +0061, o valor 0 x 6 1, enquanto ' ä ' tem dois bytes (0 x c 30 x a 4) que representam uma literal a trema, U +00 E4, valor 0 x e 4.

Vários escapes de barra invertida permitir valores arbitrários para ser codificado como texto ASCII. Há quatro formas de representar o valor inteiro como uma constante numérica: \ x seguido por exatamente dois

Page 224: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

dígitos hexadecimais; \ u, seguido por exatamente quatro dígitos hexadecimais; \ U seguido por exatamente oito dígitos hexadecimais, e uma barra invertida simples \ seguido por exatamente três dígitos octais. Em cada caso, o valor do literal é o valor representado pelos dígitos na base correspondente.

Embora essas representações tudo resultar em um número inteiro, eles têm diferentes intervalos válidos. Escapes Octal deve representar um valor entre 0 e 255, inclusive. Escapes hexadecimais satisfazer essa condição pela construção. Os escapes \ u e \ U representam pontos de código Unicode para que dentro deles alguns valores são ilegais, em especial os acima 0 x 1 0 F F F F e metades substitutos.

Depois de uma barra invertida, certas fugas de caracteres simples representam valores especiais:

Todas as outras sequências começam com uma barra invertida são literais runes dentro ilegais.

\a U+0007 alerta ou sino\b U+0008 retrocesso\f U+000C alimentação de formulário\n U+000A alimentação de linha ou de nova linha\r U+000D retorno de carro\t U+0009 guia horizontal\v U+000b tabulação vertical\\ U+005c barra invertida\' U+0027 aspas simples (escape válido somente dentro de literais de runes)\" U+0022 aspas duplas (escape válido somente dentro strings literais)

Todas as outras sequências começam com uma barra invertida são literais runes dentro ilegais.

rune_lit = "'" ( unicode_value | byte_value ) "'" .

unicode_value = unicode_char | little_u_value | big_u_value | escaped_char .byte_value = octal_byte_value | hex_byte_value.octal_byte_value = `\` octal_digit octal_digit octal_digit .hex_byte_value = `\` "x" hex_digit hex_digit .little_u_value = `\` "u" hex_digit hex_digit hex_digit hex_digit .big_u_value = `\` "U" hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit .escaped_char = `\` (“a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ).

'a''ä''本''\t''\000''\007''\377''\x07''\xff''\u12e4''\U00101234''aa' / / ilegal muitos caracteres'\xa' / / ilegal muito poucos dígitos hexadecimais'\0' / / ilegal muito poucos dígitos octais'\uDFFF' / / ilegal metade substituto'\U00110000 / / ilegal inválido ponto de código Unicode

Os operadores

Operadores combinar operandos em expressões. Expression = UnaryExpr | Expression binary_op UnaryExpr . UnaryExpr = PrimaryExpr | unary_op UnaryExpr .

binary_op = "| |" | "&&" | rel_op | add_op | mul_op .

Page 225: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

rel_op = "==" | "=" | "<" | "<=" | ">" | "> =". add_op = "+" | "-" | "|" | "^". mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "& ^". unary_op = "+" | "-" | "!" | "^" | "*" | "E" | "<-".Comparações são discutidas em outro lugar. Para outros operadores binários, os tipos de operando deve ser idêntico a menos que a operação envolve turnos ou sem tipo constantes.O operando da direita em uma expressão de mudança deve ser do tipo inteiro sem sinal ou ser uma constante sem tipo que pode ser convertido para tipo inteiro sem sinal. Se o operando esquerdo de uma expressão de mudança não constante é uma constante sem tipo, o tipo da constante é o que seria se a expressão turno foram substituídas por seu operando esquerda sozinho. s uint var = 33 var i = 1 << s / / 1 tem tipo int var j int32 = 1 << s / / 1 tem o tipo int32; j == 0 var k = uint64 (1 << s) / / 1 tem o tipo uint64; k == 1 << 33 var int m = 1,0 << s / / 1,0 tem o tipo int var n = 1,0 << s = i / / 1,0 tem o tipo int;! n == false se ints são 32bits em tamanho var o = 1 << s << == 2 s / / 1 e 2 têm tipo int; o == true se ints são 32bits em tamanho

var p = 1 << s == 1 << 33 / / ilegal se ints são 32bits de tamanho: 1 tem o tipo int, mas um << 33 overflows int var u = 1,0 << s / / ilegal: 1.0 tem tipo float64, não pode mudar ! var u1 = 1,0 << s = 0 / / ilegal: 1.0 tem tipo float64, não pode mudar var u2 = 1 << s = 1.0 / / ilegal: 1 tem o tipo float64, não pode mudar var v float32 = 1 << s / / ilegal: 1 tem o tipo float32, não pode mudar var w int64 = 1,0 << 33 / / 1,0 << 33 é uma expressão constante mudança

(. Em contraste com a regra geral, isto poderia ser chamado de uma forma de sobrecarga de operador, além disso o operador + também existe para strings, mas fora isso Go não permite a sobrecarga de operador) / para inteiros é a divisão inteira, por exemplo: 9 / 4 -> 2.

O operador módulo% só é definido para inteiros: 9% 4 -> 1Divisão por 0 faz com que o programa deixe de funcionar, um panic de tempo de execução ocorre (se é

óbvio, em seguida, o compilador pode detectá-lo), ver Capítulo 13 para saber como testar isso corretamente.

Divisão por 0,0 com números de ponto flutuante dá um resultado infinito: + InfOs operadores aritméticos aplica a valores numéricos e de produzir um resultado do mesmo tipo que o primeiro operando. Os quatro operadores aritméticos padrão ( + , - , * , / ) se aplicam para inteiro, ponto flutuante, e tipos complexos; + também se aplica às strings. Todos os outros operadores aritméticos aplicam-se apenas números inteiros. + inteiros soma, carros alegóricos, valores complexos, strings - diferença de números inteiros, flutuantes valores complexos * inteiros de produtos, carros alegóricos, valores complexos / inteiros quociente, carros alegóricos, valores complexos % inteiros restantes

& AND bit a bit inteiros | OR bit a bit inteiros ^ inteiros bit a bit XOR & ^ inteiros pouco claras (ou não)

<< Desvio à esquerda inteiro << inteiro sem sinal >> Inteiro deslocamento para a direita >> inteiro sem sinalStrings podem ser concatenados utilizando o operador + operador ou o += operador de atribuição: s: = "oi" + string (c) s + = "e adeus"Além de Strings cria uma nova string pela concatenação dos operandos.Por dois valores inteiros x e y , o quociente inteiro q = x / y e restante r = x % y satisfazer as seguintes relações: x = q * y + r e | r | <| y |com x / y truncado para zero ( "divisão truncada" ). xyx / yx% y

Page 226: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

5 3 1 2 -5 3 -1 -2 5 -3 -1 2 -5 -3 1 -2Como exceção a esta regra, se o dividendo x é o valor mais negativo para o tipo int de x, o quociente q = x / -1 é igual a x (e r = 0). x, q int8 -128 int16 -32768 int32 -2147483648 int64 -9223372036854775808Se o divisor é uma constante, que não tem de ser igual a zero. Se o divisor é zero em tempo de execução, um panic de tempo de execução ocorre. Se o dividendo é não-negativo e divisor é uma potência constante de 2, a divisão pode ser substituído por um deslocamento para a direita, e computando o restante pode ser substituído por um bit a bit E operação: xx / 4 x 4 x% >> 2 x e 3 11 2 3 2 3 -11 -2 -3 -3 1Os operadores de deslocamento move o operando esquerdo pelo conde turno especificado pelo operando direito. Eles implementar mudanças aritméticas se o operando esquerdo é um inteiro assinado e mudanças lógicas se for um inteiro sem sinal. Não há limite superior para a contagem de deslocamento. Mudanças se comportam como se o operando da esquerda é deslocado n vezes em 1 para uma contagem de mudança de n. Como resultado, x << 1 é o mesmo que x*2 e x >> 1 é o mesmo que x/2, mas truncados para o infinito negativo.Para operandos inteiros, os operadores unary +, -, e ^ são definidos como se segue: + X é 0 + x -X negação é 0 - x ^ X bit a bit complemento é m ^ x com m = "todos os bits definidos como 1" para unsigned x e m = -1 para x assinadoPara os números de ponto flutuante e complexos, +x é igual a x, enquanto que -x é a negação dos x. O resultado de uma divisão de ponto flutuante ou complexo por zero não é especificado além do padrão IEEE-754, se um panic em tempo de execução ocorre é aplicação específica.

Existem atalhos para essas operações: b = b + a pode ser encurtado para B + = a, e o mesmo vale para - =, * =, / = e% =.

Como operadores unários para números inteiros e floats temos + + (incremento) e - (decremento), mas somente após o número (postfix):

i + + é a abreviação de i + = 1 é curto para i = i + 1i - é curto para i - = 1 é curto para i = i - 1Além disso + + e - só podem ser utilizados como declarações, e não expressões, de modo n = i + + é

inválido, e as expressões mais sutis, como f (i + +) ou A [i] = b [i + +], que são aceitos em C, C + + e Java, não pode ser usado em Go.

Nenhum erro é gerado quando um estouro ocorre durante uma operação: bits altos são simplesmente descartados. As constantes podem ser de grande ajuda aqui, e se você precisa de números inteiros ou números racionais de tamanho ilimitado (que é limitada apenas pela memória disponível), você pode usar o pacote grande da biblioteca padrão, que fornece os tipos big.Int e big.Rat.

Os números aleatórios

Alguns programas, como jogos ou aplicações estatísticas precisam de números aleatórios. O rand pacote implementa geradores de números pseudoaleatórios.

Para um exemplo simples veja a Listagem 4.10-random.go, que imprime 10 inteiros não negativos aleatórios.

package main import (

“fmt”“rand”“time”

)

Page 227: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func main( ) {

for i := 0; i < 10; i++ { a := rand.Int( ) fmt.Printf(“%d / “, a)

} for i := 0; i < 5; i++ {

r := rand.Intn(8) fmt.Printf(“%d / “, r)

} fmt.Println( ) timens := int64(time.Now( ).Nanosecond( )) rand.Seed(timens) for i := 0; i < 10; i++ { fmt.Printf(“%2.2f / “, 100*rand.Float32( ))

}}

Saída, por exemplo:

816681689/1325201247/623951027/478285186/1654146165 /1951252986/2029250107/762911244/1372544545/591415086 / / 3/0/6/4/2 / 22,10/ 65,77 / 65,89 / 16,85 / 75,56 / 46,90 / 55,24 / 55,95 / 25,58 / 70,61 /

As funções rand.Float32 e rand.Float64 retornar um número pseudoaleatório desse tipo em [0.0, 1.0),), aqui, significa o limite superior não incluídas. O rand.Intn função recebe um int n e retorna um número pseudoaleatório não-negativo em [0, n).

Você pode usar a semente (valor)-função para fornecer um valor inicial para a geração pseudoaleatório.

Muitas vezes, o tempo de deslocamento atual em nano segundos é usado para essa estreitolidade.

Operadores e precedência

Alguns operadores têm prioridade (precedência) do que os outros; operadores binários do mesmo associado precedência da esquerda para a direita. A tabela abaixo lista todos os operadores e sua precedência, de cima para baixo (7 -> 1) é maior para o menor:

Precedência Operador (s)

7 ^ !6 * / % << >> & &^5 + - | ^4 == != < <= >= >3 <-2 &&1 ||

É, claro, permitido para esclarecer expressões usando ( ) para indicar a prioridade em operações: expressões contidas em ( ) são sempre calculados em primeiro lugar.

4.5.4.Tipos Aliasing

Quando se trabalha com os tipos, um tipo também pode ter um nome, de modo que este novo nome pode ser utilizado no código (para encurtar os nomes, ou evitar um nome-choque).

Em type TZ int TZ é declarado como um novo nome para o tipo int (talvez ela representa fusos horários em um programa), e pode, então, ser usado para declarar int-variáveis, como no seguinte

Page 228: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

programa:

package mainimport “fmt”type TZ intfunc main( ) { var a, b TZ = 3, 4 c := a + b fmt.Printf(“c has the value: %d”, c) / / prints: c has the value: 7}

Na verdade este alias é um novo tipo, que pode ter métodos que o tipo original não tem; TZ pode ter um método para a saída do fuso-info, de forma clara ou bonita.

Tipo de caractere

Estritamente falando, isso não é um tipo de Go: caracteres são um caso especial de números inteiros. O tipo byte é um alias para uint8, e isso é ok para o ASCII codificação tradicional de caracteres (1 byte): byte var ch = 'A'; um personagem é cercado por aspas simples ''.

Na mesa-ASCII o valor decimal para A é 65, e valor hexadecimal é 41, então o seguinte são também as declarações para o personagem A:

var ch byte = 65 or var ch byte = ‘\x41’(\ X é sempre seguido por exatamente dois dígitos hexadecimais).

Outra notação possível é a \ seguido por exatamente três dígitos octais, por exemplo, '\ 377'.Mas existe também o suporte para Unicode (UTF-8): personagens também são chamados de pontos

de código Unicode ou runes, e um caractere Unicode é representado por um int na memória. Na documentação são comumente representados como U + hhhh, onde h nos um dígito hexadecimal. Na verdade, o tipo de rune existe no Go e é um apelido para o tipo int32.

Para escrever um Unicode caracteres em código prefácio o valor hexadecimal com \ u ou \ U.Porque eles precisam de pelo menos 2 bytes, temos que usar o int16 ou tipo int.  Se forem necessários

4 bytes para o personagem \ U é usado; \ u é sempre seguido por exatamente quatro dígitos hexadecimais e \ U por 8.

O código a seguirvar ch int = '\ u0041'var ch2 int = '\ u03B2'var ch3 int = '\ U00101234'fmt.Printf ("% d -% d -% d \ n", ch, CH2, CH3) / / inteirofmt.Printf ("% c -% c -% c \ n", ch, CH2, CH3) / / personagemfmt.Printf ("% X - X% -% X \ n", ch, CH2, CH3) / / UTF-8 bytesfmt.Printf ("% U - U% -% U", ch, CH2, CH3) / / UTF-8 ponto de código

Imprime:

65 – 946-1053236A - B- r41 - 3B2 - 101234L 0041 - U +03 B2 - U 101234

Em formato de strings% c é usado como um especificador de formato para os personagens: o personagem é mostrado, de formato-especificadores% v ou% d mostrar o número inteiro que representa o caractere;% U exibe a notação hhhh U +.

O unicode pacote tem algumas funções úteis para caracteres de teste, como o (ch é um personagem):

testes para a letra: unicode.IsLetter (ch)testando por um dígito: unicode.IsDigit (ch)

Page 229: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

teste para um personagem espaços em branco: unicode.IsSpace (ch)

Eles retornam um valor booleano. O pacote utf8 contém mais funções para trabalhar com runes.

Strings

Strings são uma sequência de caracteres UTF-8 (o ASCII-código 1 byte é usado quando possível, quando necessário, um 2-4 byte de código UTF-8). UTF-8 é a codificação mais utilizado, a codificação padrão para arquivos de texto, arquivos XML e JSON strings. Embora capaz de representar caracteres que precisam de 4 bytes, ASCII-personagens ainda são armazenados usando apenas 1 byte. Uma sequência de Go é, assim, uma sequência de caracteres de largura variável (cada 1 a 4 bytes, ver Ex. 4.6), ao contrário do strings em outras linguagens como C + +, Java ou Python que são de largura fixa (Java usa sempre 2 bytes). As vantagens são que as strings Go e arquivos de texto ocupam menos espaço de memória / disco, e uma vez que UTF-8 é o padrão, Go não precisa codificar e cadeias de decodificar como outros idiomas tem que fazer.

Strings são tipos de valor e imutável: uma vez criado não pode modificar o conteúdo da string; formulada de outra maneira: strings são arrays imutáveis de bytes.

2 tipos de strings literais existem:

Strings interpretadas: cercado por "" (aspas duplas),

Sequências de escape são interpretadas, por exemplo: \ n representa uma nova linha\ r representa um retorno de carro\ t representa um separador\ u ou \ U Unicode caracteres

O caractere de escape \ também pode ser usado para remover o significado especial da seguinte personagem, então \ "simplesmente imprime a", e \ 'is', \ \ prints a \

Raw strings:

Cercado por ''(aspas volta: AltGr + £), eles não são interpretados, pois eles pode abranger várias linhas.

Em `Esta é uma string \ n` raw \ n não é interpretado, mas tomado literalmente.Strings são delimitadas de comprimento e não terminar por um caractere especial, como em C / C + +O valor inicial (default) de uma string é a string vazia "".Os operadores de comparação habituais (== != << => =>) Trabalhar em strings através da comparação

byte por byte na memória. O comprimento de uma cadeia de str (o número de bytes) é dado pela função len ( ): len (str)

O conteúdo de uma string (o bytes 'crua') é acessível através de métodos de indexação padrão, o índice entre [ ], com o índice a partir de 0:

o primeiro byte de um str cadeia é dada por: str [0]o byte i-th por: str [i]o último byte por: str [len (str) -1]

No entanto, estes traduzir apenas a personagens reais, se forem utilizados apenas caracteres ASCII!Nota: Tomar o endereço de um caractere em uma string, como & str [i], é ilegal.

Adicionando (concatenando)strings: +

Duas sequências S1 e S2 podem ser feitas em uma string s com:

Page 230: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

s: = s1 + s2s2 é anexado a S1 para formar uma nova string s.

Strings multilinha pode ser construído como se segue:

str := "Início da string" + "segunda parte da string "

O + tem que estar na primeira linha, devido à inserção de; pelo compilador.A acrescentar taquigrafia + = também pode ser usado para strings:s: = "hel" + "lo"s + = "world!"fmt.Println (s) / / “hello, world!”

Concatenação de strings em um loop usando + não é a forma mais eficiente, a melhor abordagem é usar strings.Join ( ) , o melhor mesmo é usar a escrita em um buffer de bytes . Depois, vamos ver que as strings podem ser considerados como slices(slices) de bytes (ou inteiros), e que as operações de slice de indexação, assim, também se aplicam para strings.

O cstrings e ConvCad pacote

Strings são uma estrutura de dados básica, e cada língua tem uma série de funções pré-definidas para manipulação de strings. Em Go estes estão reunidos nas strings do pacote.

Algumas funções muito úteis são:

Testes HasPrefix se a string s começa com o prefixo: strings.HasPrefix (s, prefix string) boolTestes HasSuffix quer fim da string s com o sufixo: strings.HasSuffix (s, string sufixo) bool

package main

import (“fmt”“strings”)

func main( ) {

var str string = "Este é um exemplo de uma cadeia"fmt.Printf ("T / F? Será que a string \"% s \ "tem prefixo% s?", str, "th")fmt.Printf ("% t \ n", strings.HasPrefix (str, "Th"))}

Saída: T / F? Será que a string "Este é um exemplo de uma cadeia" têm prefixo Th? Verdadeiroa. Isto ilustra também o uso da fuga caractere \ para a saída de um literal "com \", e uso de duas substituições em um formato de string.

Indicando em qual posição (índice) uma substring ou caractere ocorre em uma string:

Índice retorna o índice da primeira ocorrência de str em s, ou -1 se str não está presente em s: strings.Index (s, string str) intLastIndex retorna o índice da última instância de str em s, ou -1 se str não está presente em s: strings.LastIndex (s, string str) int

Page 231: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Se ch é um não ASCII caráter usa strings.IndexRune (s

Um exemplo:

package main import (

“fmt” “strings”

) func main( ) {

var str string = “Hi, I’m Marc, Hi.” fmt.Printf(“The position of \“Marc\” is: “) fmt.Printf(“%d\n”, strings.Index(str, “Marc”)) fmt.Printf(“The position of the first instance of \“Hi\” is: “) fmt.Printf(“%d\n”, strings.Index(str, “Hi”)) fmt.Printf(“The position of the last instance of \“Hi\” is: “) fmt.Printf(“%d\n”, strings.LastIndex(str, “Hi”)) fmt.Printf(“The position of \“Burger\” is: “) fmt.Printf(“%d\n”, strings.Index(str, “Burger”))

A posição de "Marc" é: 8A posição da primeira ocorrência de "Oi" é: 0A posição da última ocorrência de "Oi" é: 14A posição de "Burger" é: -1

Substituição de um texto:

Com strings.Replace (str, old, new, n), você pode substituir as primeiras n ocorrências de idade em str por novos. Uma cópia de str é retornado, e se n = -1 todas as ocorrências são substituídos.

Contar o número de casos não-sobrepostas de substring str em s com: strings.Count (s, string str) intUm exemplo:

package main

import ( “fmt” “strings”)func main( ) { var str string = “Hello, how is it going, Hugo?” var manyG = “gggggggggg” fmt.Printf(“Number of H’s in %s is: “, str) fmt.Printf(“%d\n”, strings.Count(str, “H”)) fmt.Printf(“Number of double g’s in %s is: “, manyG) fmt.Printf(“%d\n”, strings.Count(manyG, “gg”))

Saída:

Número de H's está em Hello, how is it going, Hugo? é: 2Número de g's da dupla em gggggggggg é: 5

Repetição de uma string:

Page 232: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Repeat retorna uma nova string que consiste de cópias contagem da string s: strings.Repeat(s, count int) string

Um exemplo:

package mainimport ( “fmt” “strings”)

func main ( ) { var origS string = “Hi there!”

var newS string newS = strings.Repeat(origS, 3) fmt.Printf(“The new repeated string is: %s\n”, newS)

}}Saída:A nova sequência repetida é: Hi there! Hi there! Hi there!

Alterar o estado de uma string:

ToLower retorna uma cópia da string s com todas as letras Unicode mapeados para o seu caso mais baixo:

strings.ToLower (s) string

Todas as letras maiúsculas é obtida com:

Um exemplo:

package mainimport (“fmt”“strings”)func main( ) {var orig string = “Hey, how are you George?”var lower stringvar upper stringfmt.Printf ("A string original é:% s \ n", orig)lower= strings.ToLower (orig)fmt.Printf ("A sequência de letras minúsculas é:% s \ n", menor)upper = strings.ToUpper (orig)fmt.Printf ("A sequência de letras maiúsculas é:% s \ n", superior)}Saída:

A string original é: Hey, how are you George? (Ei, como você está George?)A sequência de letras minúsculas é: hey, how are you george? (ei, como você está George?)A sequência de letras maiúsculas é: HEY, HOW ARE YOU GEORGE? (EI, COMO VOCÊ ESTÁ

GEORGE?)

Corte uma string:

Aqui você pode usar strings.TrimSpace (s) para remover todos os líderes e espaços em branco, se você quiser especificar em um corte que personagens string para retirar, use strings.Trim (s, "corte").

Page 233: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Exemplo: strings.Trim (s, "\ r \ n") remove todas esquerda e à direita \ r \ n da string s. A segunda string de parâmetro pode conter quaisquer caracteres, que são todos retirados da esquerda e do lado direito de s. Se você quiser remover apenas à esquerda ou à direita apenas caracteres ou strings, use TrimLeft ou TrimRight.

Dividindo a string:

No espaço em branco: strings.Fields (s) divide a string s em torno de cada instância de um ou mais caracteres de espaço em branco consecutivos, retornando uma slice de substrings [ ] colar de s ou uma lista vazia se s contém apenas espaço em branco.

Em um separador de sep: strings.Split(s, sep): funciona da mesma forma Fields, mas se divide em torno de um caractere separador ou string sep.

Juntando sobre uma slice:

Isso resulta em uma string com todos os elementos da , separados por setembro:

Strings.Join(sl [ ]string, sep string)

Estas operações simples são ilustrados na Listagem

package mainimport ( “fmt” “strings”)func main( ) { str := “The quick brown fox jumps over the lazy dog” sl := strings.Fields(str) fmt.Printf(“Splitted in slice: %v\n”, sl) for _, val := range sl { fmt.Printf(“%s - “, val) } fmt.Println( ) str2 := “GO1|The ABC of Go|25” sl2 := strings.Split(str2, “|”) fmt.Printf(“Splitted in slice: %v\n”, sl2) for _, val := range sl2 { fmt.Printf(“%s - “, val) } fmt.Println( ) str3 := strings.Join(sl2,”;”) fmt.Printf(“sl2 joined by ;: %s\n”, str3) }

/ * Saída:

Parceladas em slice: [The quick brown fox jumps over the lazy dog]The - quick - brown - fox - jumps - over - the - lazy - dog -Parceladas em slice: [GO1 The ABC of Go 25]GO1 - The ABC of Go - 25 -sl2 juntaram : GO1;The ABC of Go;25* /

Page 234: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Leitura de uma string:

O pacote tem também uma função strings.NewReader (str). Este procuces um apontador para um valor Reader, que fornece, entre outras, as seguintes funções de operar em str:

Read( ) para ler um [ ]byte ReadByte ( ) e ReadRune ( ) : Para ler o próximo byte ou rune da string.

Conversão de e para uma string:

Esta funcionalidade é oferecida pelo pacote ConvCad.Ele contém algumas variáveis para calcular o tamanho em bits de um int da plataforma em que o

programa é executado: strconv.IntSizePara converter uma variável de um determinado tipo T para uma string sempre terá êxito.Para a conversão de números que têm as funções seguintes:

strconv.Itoa (i int) string: Retorna a representação de string decimal de istrconv.FormatFloat (f float64, byte fmt, prec int, Bitsize int) string: converte o número de ponto

flutuante de 64 bits f para uma cadeia, de acordo com o formato fmt (pode ser 'b', 'e', 'f' ou 'g'), precisão e prec Bitsize é de 32 para float32 ou 64 para float64.

Convertendo uma string para um outro tipo tp nem sempre será possível, nesse caso, um erro de tempo de execução é lançada: analisar "...": argumento inválido

Para a conversão de números que têm as funções seguintes:strconv.Atoi (s string) (i int, err error) : Converter para um intstrconv.ParseFloat (s string, Bitsize int) (f float64, err error) : Converter para a64bit número de ponto flutuante

Como pode ser visto a partir do tipo de retorno destas funções retornará dois valores: o valor convertido (se possível) e da eventual erro. Assim, ao chamar essa função a forma atribuição múltipla será usado: val, err = strconv.Atoi (s)

Neste programa nós desconsiderar a possível conversão de erros com o identificador em branco _:

Package mainimport ( “fmt” “strconv”)func main( ) { var orig string = “222” var an int var newS string fmt.Printf(“The size of ints is: %d\n”, strconv.IntSize) an, _ = strconv.Atoi(orig) fmt.Printf(“The integer is: %d\n”, an) an = an + 5 newS = strconv.Itoa(an) fmt.Printf(“The new string is: %s\n”, newS)}

/ * Saída:O tamanho de inteiros é: 32O inteiro é: 222A nova sequência é: 671 * /

Page 235: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Os tempos e datas

O pacote de tempo dá-nos uma time.time tipo de dados (para ser utilizado como um valor) e funcionalidade para exibir e medir o tempo e datas.

A hora atual é dada por Time.now ( ), e as partes de uma vez pode ser obtido como t.Day ( ), t.Minute ( ), etc., você pode fazer o seu próprio tempo-formatos como em:

fmt.Printf(“%02d.%02d.%4d\n”, t.Day( ), t.Month( ), t.Year( )) / / e.g.: 21.07.2011O tipo Duração representa o tempo decorrido entre dois instantes como uma contagem nanossegundo

int64.O tipo de Mapas de localização instantes para a zona em uso naquele tempo, UTC representa Horário

Coordenado Universal.Há uma função pré-definida função (t Time) Format (string layout) string, que formata um tempo t em

uma sequência de acordo com uma sequência de layout, com alguns formatos pré-definidos, como time.ANSIC ou time.RFC822 O layout geral define o formato de que mostra a representação de um padrão de tempo, o qual é então usado para descrever o momento a ser formatado, esta parece estranho, mas um exemplo torna isso claro:

fmt.Println(t.Format(“02 Jan 2006 15:04”)) / / outputs now: 21 Jul 2011 10:31

package mainimport (

“fmt” “time”

)

var wike time.Durationfunc main( ) {

t := time.Now( ) fmt.Println(t) / / Por exemplo, Qua 21 de dezembro 09:52:14 +0100 RST 2011 fmt.Printf(“%02d.%02d.%4d\n”, t.Day( ), t.Month( ), t.Year( )) / / 21.12.2011 t = time.Now( ).UTC( ) fmt.Println(t) fmt.Println(time.Now( )) / / Qua 21 de dezembro 09:52:14 +0100 RST 2011

/ / Calcular tempos:

week = 60 * 60 * 24 * 7 * 1e9 / / Deve estar em nano segundosweek_from_now: = t.Add (week )fmt.Println (week_from_now) / / Qua 28 dez 0000 08:52:14 UTC 2011

/ / formatação de tempo:

fmt.Println (t.Format (time.RFC822)) / / 21 11 dezembro 0852 UTCfmt.Println (t.Format (time.ANSIC)) / / Qua 21 dez 2011 08:56:34fmt.Println (t.Format (“02 Jan 2006 15:04”)) / / 21 de dezembro de 2011 08:52s: = t.Format ("20060102")fmt.Println (t, "=>", s) / / Qua 21 dez 0000 08:52:14 UTC 2011 => 20111221}

A saída é mostrada após o / / em cada linha.

Ponteiros

Ao contrário de Java e NET, Go dá o controle programador sobre o qual estrutura de dados é um

Page 236: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

ponteiro e que não é, no entanto você não pode calcular com valores de ponteiros em programas. Ao dar o controle sobre o layout básico programador memória, Go oferece-lhe a capacidade de controlar o tamanho total de um determinado conjunto de estruturas de dados, o número de alocações e os padrões de acesso à memória, os quais são importantes para a construção de sistemas que executam bem: ponteiros são importantes para o desempenho e indispensável se você quer fazer programação de sistemas, perto do sistema operacional e de rede.

Porque ponteiros são um tanto desconhecido para OO-programadores contemporâneos, vamos explicá-las aqui e nos próximos capítulos de profundidade.

Valores armazenar programas na memória, e cada bloco de memória (ou palavra) tem um endereço, que normalmente é representado como um número hexadecimal, como 0x6b0820 ou 0xf84001d7f0

Go tem o operador de endereço e, que, quando colocado antes de uma variável nos dá o endereço de memória daquela variável.

O seguinte trecho de saídas de código por exemplo: "Um número inteiro: 5, a sua localização na memória: 0x6b0820" (este valor será diferente cada vez que você executar o programa!)

var i1 = 5fmt.Printf ("Um inteiro:% d, sua localização na memória:% p \ n", i1, e i1)

Este endereço pode ser armazenado num tipo de dados especial chamado ponteiro, neste caso, é um indicador de um int, aqui i1: este é denotado por * int. Se chamarmos esse ponteiro INTP, podemos declará-la como

var intp *int

Então, o seguinte é verdadeiroo: intp = & i1, intP aponta para i1.(Por causa de seu nome um ponteiro é representado por% p em um formato de string)

intP armazena o endereço de memória do i1, que aponta para a localização do i1, ele faz referência a i1 variável.

Uma variável ponteiro contém o endereço de memória de um outro valor: ele aponta para esse valor na memória e leva 4 bytes em máquinas de 32 bits, e 8 bytes em máquinas de 64 bits, independentemente do tamanho do valor que eles apontam. Claro ponteiros podem ser declarados com um valor de qualquer tipo, seja ele primitivo ou estruturado, o * é colocado antes do tipo do valor (prefixo), assim que o * é aqui um modificador de tipo.

Usando um ponteiro para referir-se a um valor que é chamado de engano.Um ponteiro recém-declarado que não tenha sido atribuído a uma variável tem o valor nulo.Uma variável ponteiro é muitas vezes abreviado como ptr.!! Em uma expressão como var p *type de sempre deixar um espaço entre o nome do ponteiro e * - tipo

var p * é sintaticamente correto, mas em expressões mais complexas, pode ser facilmente confundido com uma multiplicação!

O mesmo símbolo * pode ser colocado antes de um ponteiro como * INTP, em seguida, dá o valor que o ponteiro está apontando para, que é chamado de excluir a referência (ou conteúdo ou indireta) operador, outra maneira de dizer isso é que o ponteiro está achatada.

Assim, para qualquer variável var o seguinte é verdadeiroo: var == * (& var)Agora podemos entender o pointer.go programa completo e sua saída:

package mainimport “fmt”func main( ) { var i1 = 5 fmt.Printf ("Um inteiro:% d, a sua localização na memória:% p \ n", i1, e i1) var intp * int intp = & i1 fmt.Printf ("O valor na posição de memória% p é% d \ n", INTP, * INTP)}

Saída: Um inteiro: 5, a sua localização na memória: 0x24f0820O valor na posição de memória 5 é 0x24f0820

Page 237: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Programa dá-nos um exemplo com strings.

Isso mostra que a atribuição de um novo valor para *p altera o valor da própria variável (aqui uma string).

package mainimport “fmt”func main( ) { s := “good bye” var p *string = &s *p = “ciao” fmt.Printf ("Aqui está o ponteiro p:% p \ n", p) / / Imprime endereço fmt.Printf ("Aqui está a string * p:% s \ n", * p) / / imprime cadeia fmt.Printf ("Aqui está a sequência de s:% s \ n ", s) / / prints mesma sequência}

Saída: Aqui é o ponteiro p: 0x2540820 Aqui é a string * p: ciao Aqui é a string s: ciao

Observação: você não pode tomar o endereço de um literal ou uma constante, como o seguinte trecho de código mostra:

const i = 5ptr: = & i / / erro: não é possível obter o endereço de iptr2: = & 10 / / erro: não pode obter o endereço de 10Então Go, como a maioria dos outros de baixo nível (sistema) linguagens como C, C + + e D, tem o

conceito de ponteiros.Mas cálculos com ponteiros (chamada de aritmética de ponteiro, por exemplo ponteiro + 2, para

percorrer os bytes de uma string ou as posições em uma array), que muitas vezes levam a acesso de memória errônea em C e acidentes fatais, assim, de programas, não são permitidos em Go, tornando segura a memória de linguagem. Ponteiros Go se assemelham mais as referências de linguagens como Java, C # e VB.NET.

Assim: c = *p + + é o código inválido Go!

Uma vantagem dos ponteiros é que você pode passar uma referência a uma variável (por exemplo, como um parâmetro para uma função), em vez de passar uma cópia da variável. Ponteiros são baratos para passar, apenas 4 ou 8 bytes. Quando o programa tem que trabalhar com variáveis que ocupam muita memória, ou muitas variáveis, ou ambos, trabalhando com ponteiros podem reduzir o uso de memória e aumentar a eficiência. Variáveis destacou ainda persistem na memória, durante o tempo que existe pelo menos um ponteiro apontando para eles, então a sua vida é independente do escopo em que foram criados.

Por outro lado (mas muito menos provável), porque um ponteiro faz com que o que é chamado de um engano (uma mudança no processamento para outro endereço), uso proibitivo deles poderia causar diminuição de desempenho.

Ponteiros também pode apontar para outros ponteiros, e este aninhamento pode ser arbitrariamente profunda, de modo que você pode ter vários níveis de engano, mas na maioria dos casos, isso não contribuIrá para a clareza do seu código.

Como veremos, em muitos casos, Go torna mais fácil para o programador e vai esconder indireta como, por exemplo, realizar uma desreferenciação automática.

A desreferenciava ponteiro nulo, como nas duas linhas a seguir, é ilegal e faz uma falha de programa:

package mainfunc main( ) { var p *int = nil *p = 0}

Page 238: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

/ / No Windows: para somente com: <exit code="-1073741819" msg="process crashed"/>/ / Erro de tempo de execução: endereço de memória inválido ou nulo desreferenciava ponteiro

FLUXO DE CONTROLE

Um algoritmo é um texto estático, onde temos vários passos que são lidos e interpretados de cima para baixo. Para que venhamos a obter o(s) resultado(s) deste algoritmo, necessitamos “executá-lo”, o que resulta em um processo dinâmico.

No fluxo de controle identificamos em cada passo da execução qual é o próximo comando a ser executado.

A compreensão da lógica de programação de um algoritmo está diretamente ligada a compreensão de seu fluxo de controle. A partir de uma compreensão correta, podemos traçar as diversas execuções possíveis de um algoritmo.

Se testarmos todas essas possibilidades, e obtivermos resultados corretos, podemos ter certeza de estar entregando um produto estreitol confiável.

Os iniciantes no mundo da programação encontram alguma dificuldade em diminuir a distância conceitual que separa a representação estática de um algoritmo do(s) processo(s) dinâmico(s) de sua execução. É importante frisar que quando nos propomos a entender um algoritmo, lidamos fisicamente com um texto, mas mentalmente temos processos.

Até agora, vimos que um programa Go começa a executar em main ( ) e sequencialmente executa os comandos nessa função. Mas muitas vezes queremos executar certas declarações apenas se uma condição for satisfeita: queremos tomar decisões em nosso código. Por esta Go fornece as seguintes estruturas condicionais ou ramificação:

Se outra construção mudar caso construto selecionar construção, para a comutação entre os canaisRepetindo uma ou mais declarações (uma tarefa) pode ser feito com a estrutura iterativa ou looping: for

(intervalo) construção Algumas outras palavras-chave como break e continue podem alterar o comportamento do loop. Há também uma palavra-chave de retorno para deixar um conjunto de instruções e uma execução de um rótulo no código. Goto palavra-chave para saltar.

Go totalmente omite os parênteses (e) em torno de condições em que, switch e for-loops, criando desordem visual menor do que em Java, C + + ou C #.

A construção if else

O teste if um (um booleano ou lógico) instrução condicional: se esta for avaliada como true o corpo de instruções entre { } após o if é executado, se for false estas declarações são ignorados e a declaração após o caso é executado.

if condition { / / Fazer alguma coisa}

Em uma segunda variante de uma outra pessoa, com um corpo de afirmações cercado por { }, é anexado, que é executado quando a condição é falsa, temos então dois ramos exclusivos (apenas um deles é executado):

if condition { / / Fazer alguma coisa} Else { / / Fazer outra coisa}

Em uma terceira variante outro se a condição pode ser colocada após a outra, por isso temos três agências exclusivas:

if condition1 {

Page 239: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

/ / Fazer alguma coisa} else if condition2 { / / Fazer outra coisa} Else { / / Catch-all ou default}

O número de else e if, em princípio, não se limitando, mas por razões de legibilidade isso não deve ser exagerada. Ao utilizar este formulário, coloque a condição que é mais provável verdade pela primeira vez.

O { } são obrigatórios, também, quando há apenas uma instrução no corpo (algumas pessoas não gostam disso, mas por outro lado ela é consistente e de acordo com princípios de engenharia de software tradicionais).

O {após o if e else deve estar na mesma linha. O else if e else palavras-chave devem estar na mesma linha que o fechamento} da parte anterior da estrutura. Ambas as normas são obrigatórias para o compilador.

Est é um Go-código inválido:

if x {}else { / / INVALIDO}

Note que cada ramo é recortado com 4 (ou 8) espaços ou um guia, e que o fechamento} estão alinhados verticalmente com o caso, o que é reforçado pela aplicação de gofmt.

Enquanto ( ) em torno das condições não são necessários, para as condições de complexos que podem ser utilizados para tornar mais claro o código. A condição pode também ser composta, utilizando os operadores lógicos &&, | | e, com a utilização de ( ) para impor a precedência ou melhorar a legibilidade!.

package mainimport “fmt”func main( ) { bool1 := true if bool1 { fmt.Printf ("O valor é válido \ n") } Else { fmt.Printf ("O valor é falsa \ n") }}

/ / saída: O valor é true

Note que não é necessário teste: se bool1 == true, porque bool1 já é um valor booleano.É quase sempre melhor para testar condições verdadeiroas ou positivos, mas é possível ensaiar para o

reverso com! (Não): if bool1! ou if (condição). No último caso, o ( ) em torno a condição é muitas vezes necessário, por exemplo: if (var1 == var2).

O idioma em Go-código é omitir a outra cláusula em que o se fins em uma pausa, continuar, Go para ou retorno comunicado. Ao retornar diferentes valores de x e y ou não uma condição seja verdadeiroa uso o seguinte:

IDIOMA

if condition { return x}

return y

Observação:

Page 240: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Não use if / else com um retorno em ambos os ramos, isto não Irá compilar: "funcionar uma instrução de retorno" (é um erro de compilação ou recurso, mas fortalece o idioma termina sem acima).

Alguns exemplos úteis:

(1) Verificar se a string str está vazia:

if str == “ ” { ... }ou:if len(str) == 0 { ... }

(2) Verificar em qual sistema operacional o Go-programa é executado:Isto pode ser feito por meio de testes os runtime.GOOS constantes.

if runtime.GOOS == “windows” { ... } else { / / Unix-like ... }

Um bom lugar para fazer isso é no init ( ) função. Aqui está um trecho de código que muda um aviso para conter o "fim do input 'correto:

var prompt = "Digite um dígito, por exemplo, 3" + “ ou %s para sair.”func init( ) { if runtime.GOOS == “windows” { prompt = fmt.Sprintf(prompt, “Ctrl+Z, Enter”) } else { / / Unix-like prompt = fmt.Sprintf(prompt, “Ctrl+D”)

}}

(3) A função Abs para dar o valor absoluto de um inteiro:

func Abs(x int) int { if x < 0 { return -x } return x}

(4) Um isGreater função para comparar dois números inteiros:

func isGreater(x, y int) bool { if x > y { return true }return false}

Em uma quarta variante do se pode começar com uma declaração de inicialização (em que um valor é atribuído a uma variável). Este assume a forma (a, após a inicialização é obrigatório):

if initialization; condition { / / Fazer alguma coisa}

Page 241: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Por exemplo, em vez de:

val: = 10 if val> max { / / Fazer alguma coisa}

Você pode escrever:

if val := 10; val > max { / / Fazer alguma coisa}

Mas preste atenção que, na forma mais concisa, o val variável inicializada com: = só é conhecido dentro da instrução if (o escopo é limitado a as declarações em { }, mas se há uma outra cláusula val também é conhecido lá) : se uma variável val existia no código antes do caso, o seu valor está escondido durante o bloco if. Uma solução simples para isso é não usar: = no caso de inicialização.

package mainimport “fmt”func main( ) { var first int = 10 var cond int if first <= 0 {

fmt.Printf(“first is less than or equal to 0\n”) } else if first > 0 && first < 5 {

fmt.Printf(“first is between 0 and 5\n”) } else {

fmt.Printf(“first is 5 or greater\n”) } if cond = 5; cond > 10 { fmt.Printf(“cond is greater than 10\n”)

} else { fmt.Printf(“cond is not greater than 10\n”)

}

Saída: primeiro é 5 ou maiorcond não é maior do que 10O seguinte trecho de código mostra como o resultado de um processo function ( ) podem ser

recuperados no caso, e as medidas tomadas de acordo com o valor:

IDIOMA

if value := process(data); value > max {...if value := process(data); value > max {...}

Teste de erros em funções com múltiplos valores de retorno

Muitas vezes funções no Go são definidos de modo que eles retornam dois valores com a execução bem-sucedida: o valor era verdade, e com a execução bem sucedida: a 0 (ou o valor nulo) e falso. Em vez de verdadeiroo e falso, uma variável de erro pode ser devolvido: no caso de execução bem-sucedida, o erro é zero, caso contrário, ele contém a informação-erro. Em seguida, é óbvio para testar a execução de uma instrução if, por causa da sua notação esta é muitas vezes chamado a vírgula, por padrão.

Page 242: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

No string_conversion.go programa a strconv.Atoi função converte uma string para um inteiro. Lá nós desconsiderada um possível erro de condição com:

anInt, _ = strconv.Atoi(origStr)

Se origStr não pode ser convertida para um inteiro, a função retorna 0 para anInt, e a _ absorve o erro, o programa continua a ser executado.

Isso não é bom: um programa deve testar para cada erro que ocorre e se comportam de acordo, pelo menos, informar o utilizador (mundial) da condição de erro e voltar de, possivelmente, a função ou mesmo travar o programa.

Exemplo 1:

package mainimport ( “fmt” “strconv”)func main( ) { var orig string = “ABC” var an int var err error an, err = strconv.Atoi(orig) if err != nil { fmt.Printf(“orig %s is not an integer - exiting with error\n”, orig) return } fmt.Printf(“The integer is %d\n”, an)/ / Resto do código}

O idioma é para testar se o err variável de erro contém um erro real (se err! = Nil), nesse caso, uma mensagem apropriada é impresso era execução do programa deixa a função de executar com retorno. Também poderia ter usado a forma de retorno que retorna uma variável, como retorno err, então a função de chamada pode, neste caso, examinar o err erro.

IDIOMA

value, err := pack1.Function1(param1)if err != nil { fmt.Printf(“An error occurred in pack1.Function1 with parameter %v”, param1) return err}/ / Caso normal, continuar a execução:

Neste caso, foi main ( ) a execução, para que o programa para.Se queremos que o programa pare em caso de um erro, podemos usar a função Exit do pacote de

sistema operacional em vez de retorno:

IDIOMA

if err != nil { fmt.Printf(“Program stopping with error %v”, err) os.Exit(1)}

(O número inteiro que é dado para sair, aqui 1, pode ser testado em cima no script fora do programa)Às vezes, esse idioma é repetido várias vezes em sucessão.

Page 243: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Sem outra filial está escrito: se não houver um erro de condição, o código simplesmente continua a execução após o se { }.

Exemplo 2: nós tentamos abrir um nome de arquivo para somente leitura com os.Open:

f, err := os.Open(name)if err !=nil {return err}doSomething(f) / / No caso de nenhum erro, o ficheiro f é passado para uma função doSomething

Exemplo 3: a produção eventual de um erro pode ocorrer na inicialização de um if:

IDIOMA

if err := file.Chmod(0664); err !=nil { fmt.Println(err) return err}

(Este é um exemplo Unix, chmod de tentativas pacote de sistema operacional para alterar o modo de um arquivo)

Exemplo 4: a inicialização também pode conter uma atribuição múltipla onde ok é um retorno de valor bool, que é testada, como a da seguinte forma:

IDIOMA

if value, ok := readData( ); ok {...}

Observação: Se você acidentalmente esquecer um parâmetro à esquerda do sinal = de uma chamada de função multi-retorno, como no seguinte trecho:

func mySqrt(f float64) (v float64, ok bool) {if f < 0 { return } / / Caso de erro return math.Sqrt(f),true}func main( ) {

t := mySqrt(25.0) fmt.Println(t)

}

em seguida, você obter o seguinte erro de compilação: multiple-value mySqrt ( ) em de valor únicocontexto Ele deve ser:

t, ok: = mySqrt (25,0)if ok {fmt.Println (t)}

Observação 2:

Quando você está realmente certo de que as coisas que você está lidando são inteiros e você não quiser testar o valor de retorno em cada conversão, você pode envolver ATOI em uma função com apenas retorna o inteiro, como:

func atoi (s string) (n int) { n, _ = strconv.Atoi(s)

Page 244: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

return}

Na verdade até mesmo as simples impressão de funções de fmt. Também retornam dois valores:

count, err := fmt.Println(x) / / Número de bytes impressos, nulo ou 0, o erro

Ao imprimir para o console estes não são verificados, mas ao imprimir arquivos, conexões de rede, etc. o valor de erro deve ser sempre verificada.

A palavra-chave switch

Go totalmente omite os parênteses (e ) em torno de condições em que, switch e for-loops, criando menos desordem visual do que em Java , C + + ou C #

Em comparação com o C, Java, switch na Go é consideravelmente mais flexível. Ele toma a forma geral onde uma variável que pode ser de qualquer tipo possíveis valores que precisam ser constantes ou inteiros , mas eles devem ser do mesmo tipo ou expressões avaliar a esse tipo. Ele toma a forma geral:

switch var1 {case val1: ... ...case val2: ...default: ...}

Onde var1 é uma variável que pode ser de qualquer tipo, e val1, val2, … são possíveis valores de var1, pois eles não precisam ser constantes ou inteiros, mas eles devem ser do mesmo tipo ou expressões avaliar a esse tipo. A abertura {tem que ser na mesma linha como o switch.

Mais do que um valor pode ser testado em um caso, os valores são apresentados em uma lista separada por vírgulas, como: caso val1, val2, val3:

Cada caso ramo é exclusiva, pois eles são julgados primeiro ao último, coloque os valores mais prováveis primeiro.

O primeiro ramo que está correto é executado e, em seguida, o comando switch é completa: a ruptura com C + +, Java e C # acontece, mas está implícito, sem dúvida, um grande avanço!

Queda-through Então automático não é o comportamento padrão, se você quer isso, use a palavra-chave fallthrough no estreitol do ramo.

switch i {case 0: / / sempre que estojo vazio, nada é executado quando i == 0case 1:f ( ) / / f não é chamado quando i == 0!}

E:

switch i {case 0: fallthroughcase 1: f( ) / / f é chamado quando i == 0!}

Fallthrough também pode ser usado em uma hierarquia de casos em que em cada nível algo tem de ser feito em adição ao código já executado em casos de maior dimensão, e quando também uma ação

Page 245: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

padrão tem de ser executado.Após o caso … : Várias instruções podem seguir sem que eles sejam cercados por { }, mas chaves são

permitidas. Quando há apenas uma instrução: ele pode ser colocado na mesma linha de processo.A última declaração de tal corpo também pode ser um retorno com ou sem expressão.Quando termina com uma instrução de retorno, também tem que ser uma instrução de retorno após o}

do switch.O (opcional) ramo default é executado quando nenhum valor for encontrado para combinar com var1,

assemelha-se a cláusula else em declarações if-else. Ele pode aparecer em qualquer lugar do switch (mesmo como primeiro ramo), mas o melhor é escrito como o último ramo.

package mainimport “fmt”func main( ) { var num1 int = 100 switch num1 { case 98, 99: fmt.Println(“It’s equal to 98”) case 100: fmt.Println(“It’s equal to 100”) default: fmt.Println(“It’s not equal to 98 or 100”) }}

/ / Output: "É igual a 100"

Em uma segunda forma de uma switch nenhuma variável é necessária (isto é, de fato, um switch true) e os casos podem testar diferentes condições. A primeira condição que é verdade é executado. Isso se parece muito com o encadeamento if-else, e oferece uma sintaxe mais legível se há muitos ramos.

switch { case condition1:

... case condition2:

... default:

...}

Por exemplo:

switch {case i < 0: f1( )case i == 0: f2( )case i > 0: f3( )}

Qualquer tipo que suporta o operador de comparação de igualdade, tal como ints, strings ou apontadores, pode ser utilizado nestas condições.

Listagem 5.5-switch2.go:package mainimport "fmt"função main ( ) {var num1 int = 7switch {

Page 246: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

caso num1 <0:fmt.Println ("Número é negativo")caso num1> 0 && num1 <10:fmt.Println ("Número é entre 0 e 10")default:fmt.Println ("Número é 10 ou maior")}}

/ / Saida: Número está entre 0 e 10

Como terceira forma e como o caso, um switch também pode conter uma instrução de inicialização:

switch initialization { case val1: ... case val2: ... default: ...

}

Isso pode misturar muito bem com os testes caso de condições, como em:

switch result := calculate( ); {case result < 0: / / ...case result > 0: / / ...default: / / 0}

Ou esse trecho, onde a e b são recuperados na inicialização paralela, e os casos são condições:

switch a, b := x[i], y[j]; {case a < b: t = -1case a == b: t = 0case a > b: t = 1}

Há também um switch de tipo que testa o tipo de uma variável de interface.Pergunta 5.1: Dê a saída do seguinte trecho de código:

k := 6switch k {case 4: fmt.Println(“was <= 4”); fallthrough;case 5: fmt.Println(“was <= 5”); fallthrough;case 6: fmt.Println(“was <= 6”); fallthrough;case 7: fmt.Println(“was <= 7”); fallthrough;case 8: fmt.Println(“was <= 8”); fallthrough;default: fmt.Println(“default case”)}

A para construção

Somente a instrução for existe para repetir um conjunto de instruções um número de vezes, o que é

Page 247: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

possível, porque é mais flexível do que em outras línguas. Uma passagem através do conjunto é chamado de iteração.

Observação: Não há for-match para o Go enquanto instrução encontrada na maioria dos outros idiomas, provavelmente por causa do caso de uso para ele não era tão importante.

iteração controlada por contador

A forma mais simples é a iteração contra-controlado, como em for1.go:O formato geral é: for init; condition; modif { }

package mainimport “fmt”func main( ) { for i := 0; i < 5; i++ { fmt.Printf(“This is the %d iteration\n”, i) }}

Saída:

Esta é a iteração 0Esta é a iteração 1Este é o iteração 2Esta é a iteração 3Este é o iteração 4

O corpo { } do loop for é repetido um número conhecido de vezes, isso é contado por uma variável (aqui i). As partidas de alça (por isso está é realizada apenas uma vez) com uma inicialização para i (i: = 0), o que é mais curto do que uma declaração de antemão. Isto é seguido por uma verificação condicional em i (i <10), que é realizado antes de cada iteração: quando é verdadeiroa, a iteração é feito, o loop for pára quando a condição se torna falsa. Em seguida, trata de uma modificação do i (i + +), a qual é realizada depois de cada iteração, altura em que a condição é verificada de novo para ver se o ciclo pode continuar. Essa modificação pode por exemplo ser também um decréscimo, ou + ou - usando um passo.

Estes são três declarações separadas que formam o cabeçalho do loop, por isso eles são separados por, mas não há nenhum ( ) ao redor do cabeçalho: for (i = 0; i <10; i + +) { } é o código inválido!

Mais uma vez a abertura {tem de estar na mesma linha que o para. A variável contador deixa de existir após a} do para, sempre use nomes curtos para ele como i, j, z ou ix.

!! Nunca mude a contra-variável no loop for em si, esta é uma prática ruim em todas as línguas!

package mainimport “fmt”func main( ) {

str := “Go is a beautiful language!” fmt.Printf(“The length of str is: %d\n”, len(str))

for ix :=0; ix < len(str); ix++ { fmt.Printf(“Character on position %d is: %c \n”, ix, str[ix])

} str2: = " 日本语" fmt.Printf(“The length of str2 is: %d\n”, len(str2))

for ix :=0; ix < len(str2); ix++ {fmt.Printf(“Character on position %d is: %c \n”, ix, str2[ix])

}}/ * Saída:

Page 248: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

O comprimento de str: 27Personagem em posição 0 é: GPersonagem em posição 1 é: oPersonagem em posição 2 é:Personagem em posição 3 é: i...Personagem em posição 25 é: ePersonagem em posição 26 é:O comprimento de cad2 é: 9Personagem em posição 0 é: AEPersonagem em posição 1 é: -Personagem em posição 2 é:Personagem em posição 3 é: AEPersonagem em posição 4 é: œPersonagem em posição 5 é: ¬Personagem em posição 6 é: éPersonagem em posição 7 é: aPersonagem em posição 8 é:?* /

Se imprimir o len comprimento de strings str e str2, temos respectivamente 27 e 9.Vemos que para caracteres ASCII normais usando 1 byte, um caractere indexado é o personagem

completo, enquanto que para caracteres não-ASCII (que precisam de 2 a 4 bytes) o caractere indexado já não está correto!

iteração controlado por Condição

A segunda forma não contém cabeçalho e é usado para controlado por condição iteração (o loop while em outras línguas), com o formato geral:

para a condição { }Você também pode argumentar que é uma seção para sem inicialização e modif, para que o; são

supérfluas.

package mainimport “fmt”func main( ) { var i int = 5 for i >= 0 { i = i - 1 fmt.Printf(“The variable i is now: %d\n”, i) }}

Saída:

A variável i é agora: 4A variável i é agora: 3A variável i é agora: 2A variável i é agora: 1A variável i é agora: 0A variável i é agora: -1

Loops infinitos

Page 249: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

A condição pode estar ausente: como em for i: = 0; i + + ou por { } (ou para; { } mas o; é removido por gofmt): estes são, de fato, loops infinitos. Este último também pode ser escrito como: for verdadeiroa { }, mas o formato normal é: para { }

Se uma verificação de condição está faltando em um para-header, a condição de loop é e permanece sempre verdadeiroo, por isso, o corpo do laço algo tem que acontecer para que o loop para ser encerrado após um certo número de iterações.

Sempre tome cuidado para que a condição de saída Irá avaliar para true em um determinado momento, a fim de evitar um loop infinito! Este tipo de laço é encerrado por uma instrução break (ver § 5.5) ou uma instrução de retorno.

Mas há uma diferença: quebrar apenas saídas do loop, enquanto as saídas de retorno da função em que o loop é codificado!

Um uso típico para um loop infinito é uma função de servidor que está à espera de receber os pedidos.Para um exemplo em que isso tudo vem junto, ver o loop for na listagem 12.17 (xml.go):

for t, err = p.Token( ); err == nil; t, err = p.Token( ) {...

}

A construção de gama

Esta é a construção do iterador em Go e você vai achar que é útil em muitos contextos. É uma variação muito útil e elegante, usado para fazer um loop sobre cada item em uma coleção. É semelhante a um foreach em outras línguas, mas ainda temos o índice a cada iteração no loop. O formato geral é: para ix, val: = gama coll { }

Tenha cuidado: val aqui uma cópia do valor em que o índice na coleção, assim que pode ser usado apenas para propósitos de leitura, o valor real da coleção não pode ser modificada através de val (tentar fazer isso!). Uma string é um conjunto de Unicode caracteres (ou runes), de modo que ele pode ser aplicado para strings também. Se str é uma string, você pode fazer um loop sobre ele com:

for pos, char := range str {...}

Cada caractere rune e seus pós índices estão disponíveis para processamento dentro do loop. Ele corompe caracteres Unicode individuais ao analisar o UTF-8 (codificações erradas consumir um byte e produzem a rune substituição U + FFFD).

-Break / continue

Usando intervalo, o código do poderia então ser reescrito para loop (claramente menos elegante) como:

for { i = i - 1 fmt.Printf(“The variable i is now: %d\n”, i)

if i < 0 { break

}}

Assim, em cada iteração uma condição (aqui i <0) tem de ser verificada para ver se o loop deve parar.Se a condição de saída torna-se verdadeiroa, o loop é deixado pela instrução break.A instrução break sempre Corrompe da estrutura mais interna em que ela ocorre, que pode ser usado

em qualquer tipo de loop for (contador, condição, etc.), mas também em um switch ou um select-statement. Execução continua após o término} dessa estrutura.

Page 250: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

No exemplo a seguir, com um loop aninhado (for4.go) break sai do loop mais interno:

Listagem 5.11-for4.go:package mainpackage mainfunc main( ) { for i:=0; i<3; i++ { for j:=0; j<10; j++ { if j>5 { break } print(j) } print(“ ”) }}

/ / Saida: 012345 012345 012345

A palavra-chave continue pula a parte restante do circuito, mas, em seguida, continua com a próxima iteração do loop após a verificação do estado de conservação:

package mainfunc main( ) { for i := 0; i < 10; i++ {

if i == 5 { continue } print(i) print(“ ”)

}}

Saída: 0 1 2 3 4 6 7 8 95 é ignorado

A palavra-chave continuar apenas pode ser utilizado dentro de uma for-loop.

A utilização de etiquetas com break e continue-empreendedores

A linha de código que começa a por, switch ou instrução select pode ser decorada com um rótulo do identificador forma:

A primeira palavra que termina com dois pontos, e que precede o código (gofmt coloca na linha anterior) é um rótulo, como LABEL1:

(O nome de um rótulo é case-sensive, ele é colocado em maiúsculas por convenção para aumentar a legibilidade.)

package mainimport “fmt”func main( ) {LABEL1: for i := 0; i <= 5; i++ { for j := 0; j <= 5; j++ { if j == 4 { continue LABEL1 }

Page 251: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

fmt.Printf(“i is: %d, and j is: %d\n”, i, j) } }}

Aqui continuar aponta para LABEL1, a execução salta para o rótulo.Você vê que os casos j == 4 e j == 5 não aparecem na saída: o rótulo precede o loop externo, que

começa i na sua próxima valor, fazendo com que o j no interior loop for para repor a 0 em sua inicialização .Da mesma forma pausa LABEL pode ser usado, não só a partir de um loop for, mas também para sair

de um switch . Existe até uma palavra-chave Goto, que tem de ser seguido por um nome de etiqueta:

package mainfunc main( ) { i:=0 HERE: print(i) i++ if i==5 { return } goto HERE}

Que imprime 01234.

Mas um goto para trás quicky leva a ilegível 'spaghetti'-código e não deve ser usado, há sempre uma alternativa melhor.

!! O uso de etiquetas e, certamente, empreendedores é desencorajado: pode levar rapidamente a má concepção do programa, o código pode ser escrito quase sempre mais legível, sem usá-los. !

Um exemplo em que o uso de Goto é aceitável é em simple_tcp_server.go programa do § 15.1: há GOTO é usado para saltar de um loop infinito de leitura e fechar a conexão com um cliente quando um erro de leitura ocorre nessa conexão.

Declarando um rótulo e não usá-lo é um erro do compilador (etiqueta ...definido e não utilizada)Se você realmente tem que usar goto, use-o apenas com rótulos para a frente (um rótulo que aparece

no código de um número de linhas após a Goto), e não declarar quaisquer novas variáveis entre os empreendedores e rótulo, porque isso pode levar a erros e resultados inesperados (não compila!):

func main( ) {a := 1goto TARGET / / erro de compilação: / / Goto TARGET salta sobre declaração de b em goto2.go: 8b := 9 TARGET:b += a fmt.Printf ("a é% v *** b é% v", a, b)}

Saída:a é 1 *** b é 4.241.844

Funções

Funções são os blocos básicos no código Go: eles são muito versáteis de modo que mesmo se pode dizer que Go tem um monte de características de uma linguagem funcional. Cada programa composto por um número de funções: é o bloco de código base.

Como o código é compilado Go a ordem na qual as funções são escritas no programa, não importa, mas para facilitar a leitura, é melhor começar com main ( ) e escrever as funções em uma ordem lógica (por exemplo, a ordem de chamada).

O seu principal objetivo é quebrar um grande problema que requer muitas linhas de código em uma

Page 252: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

série de pequenas tarefas (funções). Além disso, a mesma tarefa pode ser chamado várias vezes, de modo que uma função promove a reutilização de código.

(Na verdade, um bom programa homenageia o princípio DRY, Não se repita, o que significa que o código que executa uma determinada tarefa pode aparecer apenas uma vez no programa.)

A função termina quando ele executou a sua última declaração (antes}), ou quando ele executa uma instrução de retorno, que pode ser com ou sem argumento, estes argumentos são os valores que as funções retorna de seu cálculo. Um retorno simples pode também ser utilizado para estreitolizar um infinito loop for, ou para parar um goroutine.

Existem 3 tipos de funções em Go:

• funções normais com um identificador• Anônimo ou funções lambda• Métodos

Qualquer um destes pode ter parâmetros e valores de retorno. A definição de todos os parâmetros de função e valores de retorno, juntamente com seus tipos, é chamado a assinatura da função.

E, como um lembrete, um pré-requisito sintaxe:

Esta é inválido Go-código:

func g ( ){ / / INVALIDO}

Ele deve ser: func g ( ) {

} / / VÁLIDO

A função é chamada ou chamado em código, de uma forma geral como:

pack1.Function (arg1, arg2, ..., argn)

Onde a função é uma função no pacote pack1 e arg1, etc., são os argumentos: os valores que são passados para os parâmetros da função. Quando uma função é chamada cópias dos argumentos são feitas e estes são então passadas para a função chamada. A invocação acontece no código de outra função: a função de chamada. Uma função pode chamar outras funções, tanto quanto necessário, e estes, por sua vez chamada outras funções, e isso pode continuar com teoricamente sem limite (ou a pilha sobre a qual estas chamadas de função são colocados está esgotado). Aqui está o exemplo mais simples de uma função chamando outra função:

package mainfunc main( ) { println(“In main before calling greeting”) greeting( ) println(“In main after calling greeting”)}func greeting( ) { println(“In greeting: Hi!!!!!”)}

Saída:

In main before calling greetingIn greeting: Hi!!!!!In main after calling greeting

Uma chamada de função pode ter outra chamada de função como argumento, desde que esta função tem o mesmo número e tipos de argumentos na ordem correta que a primeira função precisa, por exemplo:

Page 253: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Suponha necessidades f1 3 argumentos f1 (a,b, c int), e F2 retornos três argumentos:

f2(a, b int) (int, int, int), então esta pode ser uma chamada para f1: f1(f2(a, b))

Sobrecarga de função, que é a codificação duas ou mais funções em um programa com o mesmo nome da função, mas uma lista de parâmetros diferente e / ou um tipo de retorno diferente (s), não é permitido em Go. Ele dá o erro do compilador:

funcname declarado novamente neste bloco, a declaração anterior no linenoA principal razão é que as funções de sobrecarga força o tempo de execução para fazer uma

correspondência de tipo adicional que reduz o desempenho, sem sobrecarga significa apenas um despacho função simples é necessário. Então, você precisa dar seus nomes originais funções apropriadas, provavelmente nomeados de acordo com a sua assinatura.

Para declarante uma função realizada fora Go, como uma rotina de montagem, basta dar o nome e assinatura, e nenhum corpo:

func FlushICache (começar, UIntPtr estreitol) / / implementado externamente

As funções também podem ser utilizados sob a forma de uma declaração, como função do tipo, como em: type binOp func(int, int) int . Neste caso também o corpo { } é omitido.

Funtions são valores de primeira classe: podem ser atribuído a uma variável, como em: add := binOpO suplemento variável obtém uma referência (pontos) para a função e sabe a assinatura da função que

se refere, de modo que não é possível atribuir-lhe uma função com uma assinatura diferente.Valores da função pode ser comparada: são iguais se eles se referem à mesma função ou se ambos

são nulas. A função não pode ser declarada dentro de outra função (sem nidificação), mas isso pode ser imitada usando funções anônimas.

Go tem até agora nenhum conceito de genéricos, o que significa, por exemplo, a definição de uma função que pode ser aplicada a um certo número de tipos de variáveis. No entanto a maioria dos casos pode ser resolvido simplesmente usando interfaces, especialmente a interface vazia e um switch tipo e / ou por meio de reflexão. A complexidade do código aumenta o uso dessas técnicas e de desempenho baixos, por isso, quando o desempenho é muito importante, é melhor e vai produzir código mais legível para criar a função explicitamente para cada tipo usado.

Parâmetros e valores de retorno

A função pode receber parâmetros para usar em seu código, e ele pode retornar zero ou mais valores (quando mais valores são devolvidos uma fala muitas vezes de uma tupla de valores). Esta é também uma grande melhoria em comparação com C, C + +, Java e C #, e é particularmente útil quando o teste ou não uma função de execução resultou em um erro

Voltando (a) valor (es) é feito com a palavra-chave de retorno. Na verdade, cada função que retorna pelo menos 1 valor deve terminar com retorno ou panic.

Código após o retorno no mesmo bloco não é mais executado. Se o retorno for usado, então todos os códigos-path na função deve terminar com uma instrução de retorno.

Chamada por valor / Call por referência

A forma padrão no Go é passar uma variável como um argumento para uma função por valor: a cópia é feita dessa variável (e os dados nele). A função trabalha com e possivelmente muda a cópia, o valor original não é alterado: Function (arg1).

Se você quiser função a ser capaz de mudar o valor da própria arg1 ('no lugar'), você tem que passar o endereço de memória daquela variável com e, esta é chamada (passar) por referência: Function (e arg1); efetivamente um ponteiro é então passada para a função. Se a variável que é passado é um ponteiro, o ponteiro é copiado, não os dados que ele aponta, mas através do ponteiro a função altera o valor original.

Passando um ponteiro (um de 32 bits ou de 64 bits valor) é na maioria dos casos mais barato do que fazer uma cópia do objeto.

Tipos de referência, como slices (CH 7), maps (8 ch), interfaces (ch 10) e canais (CH 13) são passagem por referência por padrão (mesmo que o ponteiro não é diretamente visível no código).

Page 254: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Algumas funções apenas executar uma tarefa, e não retornam valores: eles realizam o que é chamado de efeito colateral, como imprimir para o console, o envio de um e-mail, registrando um erro, etc.

Mas a maioria das funções retornam valores, que pode ser nomeado ou não.No programa simple_function.go a função recebe 3 parâmetros int a, b e c e retorna um int (as linhas

comentadas mostram código alternativo mais detalhado, onde uma variável local é usado):

package mainimport “fmt”func main( ) { fmt.Printf(“Multiply 2 * 5 * 6 = %d\n”, MultiPly3Nums(2, 5, 6)) / / var i1 int = MultiPly3Nums(2, 5, 6) / / fmt.Printf(“Multiply 2 * 5 * 6 = %d\n”, i1)}func MultiPly3Nums(a int, b int, c int) int { / / var product int = a * b * c / / return product return a * b * c}

Saída:

Multiplique 2 * 5 * 6 = 60

Quando se torna necessário voltar mais do que 4 ou 5 valores de uma função, é melhor passar uma slice (ver capítulo 7) é que os valores são do mesmo tipo (homogêneo), ou para usar um ponteiro para um struct 130The Way to Go

(Veja o capítulo 10) se eles são de tipo diferente (heterogêneo). Passando um ponteiro como o que é barato e permite modificar os dados no local.

variáveis de retorno nomeadas

No programa seguinte multiple_return.go a função recebe um parâmetro int e retorna 2ints; os valores de retorno são preenchidas em função de chamada em um trabalho paralelo.As duas funções getX2AndX3 e getX2AndX3_2 mostrar como variáveis de retorno sem nome ou

nomes são usados. Quando houver mais de uma variável de retorno sem nome, que deve ser colocado dentro de ( ), como (int, int)

Denominada variáveis utilizadas como parâmetros de resultado são automaticamente inicializados com o valor zero, e uma vez que recebem o seu valor, um (vazio) instrução de retorno simples é suficiente, além disso, mesmo quando há apenas uma variável de retorno chamado, ele tem que ser colocado dentro ( ).

package mainimport “fmt”var num int = 10var numx2, numx3 intfunc main( ) {

numx2, numx3 = getX2AndX3(num) PrintValues( ) numx2, numx3 = getX2AndX3_2(num) PrintValues( )

func PrintValues( ) {fmt.Printf(“num = %d, 2x num = %d, 3x num = %d\n”, num, numx2, numx3)}func getX2AndX3(input int) (int, int) {return 2 * input, 3 * input}func getX2AndX3_2(input int) (x2 int, x3 int) {x2 = 2 * inputx3 = 3 * input/ / Retorno x2, x3return

Page 255: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}

Saída:

num = 10, 2x num = 20, 3x num = 30num = 10, 2x num = 20, 3x num = 30

Atenção: devolver ou retorno var é ok, mas erro de sintaxe: = inesperados, ponto e vírgula esperando ou nova linha ou} retorno var = expressão dá um erro do compilador:

Mesmo com variáveis de retorno nomeados você ainda pode ignorar os nomes e valores de retorno explícitos.

Quando qualquer uma das variáveis de resultado tem sido sombra (não é uma boa prática!) O comando return deve conter os nomes das variáveis de resultado.

!!Use variáveis de retorno nomeados: eles fazem o código mais claro, mais curto e auto documentado!

identificador em branco

O identificador branco _ pode ser usada para descartar valores, de forma eficaz atribuir o valor do lado direito para nada, como em blank_identifier.go.

Os ThreeValues de função não tem parâmetros e 3 valores de retorno, onde apenas o primeiro e terceiro valor de retorno são capturados em i1 e f1.

package mainimport “fmt”func main( ) { var i1 int var f1 float32 i1, _, f1 = ThreeValues( ) fmt.Printf(“The int: %d, the float; %f\n”, i1, f1)}func ThreeValues( ) (int, int, float32) { return 5, 6, 7.5}

Saída: A int: 5, o flutuador; 7,500000

Outro exemplo de uma função com dois parâmetros e valores de retorno de 2, que calcula o valor mínimo e máximo dos parâmetros 2 é apresentado em minmax.go.

package mainimport “fmt”func main( ) {

var min, max int min, max = MinMax(78, 65) fmt.Printf(“Minimum is: %d, Maximum is: %d\n”, min, max)

}func MinMax(a int, b int) (min int, max int) {

if a < b { min = a

max = b } else { / / a = b ou a < b

min = b max = a

} return

Page 256: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}

/ / Saída: Mínima é de: 65, máxima é de: 78

Alterando uma variável fora

Passando um ponteiro para uma função não só conserva a memória, porque nenhuma cópia do valor é feita.

Ele tem também como efeito colateral que a variável ou o objeto pode ser alterado dentro de função, de modo que o objeto não tiver alterado para ser devolvido para a função. Veja este o seguinte programa pouco, onde resposta, um ponteiro para um inteiro, está a ser alterada na própria função.

package mainimport ( “fmt”)

/ / Esta função altera resposta:

func Multiply(a, b int, reply *int) {

*reply = a * b}func main( ) {

n := 0 reply := &n Multiply(10, 5, reply) fmt.Println(“Multiply:”, *reply) / / Multiplica: 50

}

Este é apenas um exemplo didático, mas é muito mais útil para mudar um grande objeto dentro de uma função. No entanto, esta técnica obscurece um pouco o que está acontecendo, o programador deve ser muito consciente deste efeito colateral e, se necessário deixar claro para os usuários da função através de um comentário.

Passando um número variável de parâmetros

Se o último parâmetro de uma função é seguido por ... tipo, isso indica que a função pode lidar com um número variável de parâmetros desse tipo, possivelmente, também 0: a chamada função de paridade variável: func myFunc (a, b, arg ... int) { }

A função recebe em virár uma slice do tipo (ver capítulo 7), o qual pode ser transmitido para o _, v: = gama construção.

Dada a função era chamada:

func Greeting(prefix string, who ...string)Greeting(“hello:”, “Joe”, “Anna”, “Eileen”)Saudação ("Olá", "Joe", "Anna", "Eileen")

Dentro de saudação, que terá o valor [ ] string {"Joe","Anna","Eileen"}

Se os parâmetros são armazenados em um arr array, a função pode ser chamada com o parâmetro arr ...

package main

Page 257: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

import “fmt”func main( ) { x := Min(1, 3, 2, 0) fmt.Printf(“The minimum is: %d\n”, x) arr := [ ]int{7,9,3,5,1} x = Min(arr...) fmt.Printf(“The minimum in the array arr is: %d”, x)}func Min(a ...int) int { if len(a)==0 { return 0 } min := a[0] for _, v := range a { if v < min { min = v } } return min}

Saída:O mínimo é: 0O mínimo na arr array é: 1

Defer e rastreamento

A palavra-chave de adiamento nos permite defer a execução de uma instrução ou uma função até o estreitol do delimitador função (chamada): ele executa alguma coisa (uma função ou uma expressão) quando a função de inclusão retornos (após cada retorno e até mesmo quando um erro ocorreu no meio de executar a função, não só um retorno no estreitol da função), mas antes do} (Por que depois?

Porque a própria declaração de retorno pode ser uma expressão que faz alguma coisa, em vez de apenas dar de volta uma ou mais variáveis).

Defer se assemelha ao bloco, estreitolmente, em OO-línguas como Java e C #, na maioria dos casos, ele também serve para liberar recursos alocados.

package mainimport “fmt”func main( ) {Function1( )}func Function1( ) {

fmt.Printf(“In Function1 at the top\n”) defer Function2( ) fmt.Printf(“In Function1 at the bottom!\n”)

}func Function2( ) { fmt.Printf(“Function2: Deferred until the end of the calling function!”)}

Saída:

Em Function1 no topoEm Function1 na parte inferior!Function2: diferido até o fim da função de chamada!(Compare a saída quando defer é removido)

Se o adiamento tem argumentos são avaliados na linha da instrução defer, o que é ilustrado no

Page 258: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

seguinte trecho, onde a defer imprimirá 0:

func a( ) { i := 0 defer fmt.Println(i) i++ return}

Quando muitos de defer são emitidos no código, eles são executados no estreitol da função, na ordem inversa (como uma pilha ou LIFO): o último adiamento é executado primeiro, e assim por diante. Isso é ilustrado no seguinte trecho artificial:

func f( ) { for i := 0; i < 5; i++ { defer fmt.Printf(“%d “, i) }}

Que imprime: 4 3 2 1 0

permite-nos garantir que certas tarefas de limpeza são realizados antes de retornar de uma função, por exemplo:

1) fechando um fluxo de arquivo:/ / Abre um arquivodefer file.Close( )

2) destravar um recurso bloqueado (mutex):mu.Lock ( )defer mu.Unlock( )

3) imprimir um rodapé em um relatório:PrintHeader ( )defer printFooter ( )

4) fechar uma conexão de banco de dados:/ / Abre uma conexão com o bancodefer disconnectFromDB( )

Pode ser útil para manter o líquido de limpeza de código e então geralmente mais curtos.A lista a seguir simula caso 4):

package mainimport “fmt”func main( ) { doDBOperations( )}func connectToDB ( ) { fmt.Println( “ok, connected to db” )}func disconnectFromDB ( ) { fmt.Println( “ok, disconnected from db” )}func doDBOperations( ) { connectToDB( ) fmt.Println(“Defering the database disconnect.”) defer disconnectFromDB( ) / / função chamada aqui com defer fmt.Println(“Doing some DB operations ...”)

Page 259: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

fmt.Println(“Oops! some crash or network error ...”) fmt.Println(“Returning from function here!”) return / /terminate the program / / Função adiada executado aqui um pouco antes, na verdade, o retorno, mesmo se há um retorno

ou estreitolização anormal antes}

/ * Saída:

ok, connected to dbDefering the database disconnect.Doing some DB operations ...Oops! some crash or network error ...Returning from function here!ok, disconnected from db* /

Rastreamento com defer:

A forma primitiva, mas às vezes eficaz de rastreamento da execução de um programa é a impressão de uma mensagem ao entrar e sair de certas funções. Isto pode ser feito com as duas funções seguintes:

func trace(s string) { fmt.Println(“entering:”, s) }func untrace(s string) { fmt.Println(“leaving:”, s) }

Onde vamos chamar untraced com a palavra-chave de defer, como no seguinte programa

package mainimport “fmt”func trace(s string) { fmt.Println(“entering:”, s) }func untrace(s string) { fmt.Println(“leaving:”, s) }func a( ) {

trace(“a”) defer untrace(“a”) fmt.Println(“in a”)

}func b( ) {

trace(“b”) defer untrace(“b”) fmt.Println(“in b”) a( )

}func main( ) {

b( )}

Saídas:

entering: bin bentering: awin aleaving: aleaving: b

Isso pode ser feito de forma mais sucinta:

package main

Page 260: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

import “fmt”func trace(s string) string { fmt.Println(“entering:”, s) return s}func un(s string) { fmt.Println(“leaving:”, s)}func a( ) { defer un(trace(“a”))

fmt.Println(“in a”)}func b( ) {

defer un(trace(“b”)) fmt.Println(“in b”) a( )

}func main( ) {

b( )}

defer_tracing2.go:

Usando defer para registrar parâmetro e retornar valores de dentro da função:Esta é uma outra possibilidade de utilização de defer o que pode vir a calhar durante a depuração:

package mainimport ( “log” “io”)func func1(s string) (n int, err error) { defer func( ) { log.Printf(“func1(%q) = %d, %v”, s, n, err) }( ) return 7, io.EOF}func main( ) { func1(“Go”)}

/ / Output: 2011/10/04 10:46:11 func1 ("Go") = 7, EOF

funções embutidas

Estas são funções pré-definidas que podem ser usadas como tal, sem ter que importar um pacote para ter acesso a eles. Eles às vezes se aplicam a diferentes tipos, por exemplo, len, tampa e acrescente, ou eles têm de operar em nível de sistema perto como panic. É por isso que eles precisam de apoio do compilador.

Aqui está uma lista, que será discutido depois.

Close Usado em canal de comunicaçãolen cap len dá o comprimento de uma série de tipos (strings, arrays, slices, maps, canais), cap é

a capacidade, o armazenamento máximo (aplicável apenas para slices e mapas) new make Ambos new e make são usados para alocação de memória: new para tipos de valor e tipos definidos pelo usuário, como estruturas. make para built-in tipos de referência (slices, maps, canais).

Page 261: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Eles são usados como funções com o tipo como seu argumento: novo (tipo),fazer (tipo)new(T) aloca armazenamento zerado para um novo item do tipo T e retorna seu endereço, para que

ele retorna um ponteiro para o tipo T.make(T) retorna uma variável inicializada do tipo T, por isso faz mais trabalho do que o novo ! new ( ) é

uma função, não se esqueça de seus parênteses!Ele pode ser usado com os tipos primitivos, bem como:v: = new (int) / / v tem o tipo int *copy append usado para copiar e concatenação de slices panic recover ambos são utilizados em um mecanismo para os erros de manipulação print println funções de impressão de baixo nível, usar o pacote fmt em produção de programas.Complexo real imag usado para fazer e manipular números complexos

funções recursivas

Funções recursivas se torna mais fácil para trabalhar com estruturas de dados recursivas (tais como árvores binárias), mas que pode ser ineficiente para, por exemplo, realizarmos cálculos numéricos. Vamos começar com um exemplo muito simples (e ineficiente), só para mostrar como recursão é feito. Quando uma função usa recursão de cauda, ou seja, quando a sua última assertion é uma chamada recursiva, podemos geralmente convertê-lo em um loop simples. Usando um loop salva a sobrecarga de chamadas de funções repetidas, embora o problema adicional de limitada espaço de pilha que pode afetar funções profundamente recursivas em algumas línguas é muito menos comum em programas de Go por causa da maneira Go gerencia a memória. Em algumas situações recursão é a melhor maneira de expressar um algoritmo.Encerramento e recursão são poderosos tecnicasde programação, que constituem a base de um paradigma conhecido como programação funcional. A maioria das pessoas vai achar programação mais difícil de entender do que uma abordagem baseada em loops, if, variveis e funções simples. Para entender melhor como isso função funciona, vamos ver um exemplo didático em Português: fatorial (2) :• É x 0 == ? Não. ( x é 2)• Encontre o fatorial de x - 1• É x 0 == ? Não. ( x é 1)• Encontre o fatorial de x - 1• É x 0 == ? Sim, retornar 1.• retorno 1 * 1• retorno 2 * 1

Uma função que se chamam em seu corpo é chamada recursiva. O exemplo notório é o cálculo do número da sequência de Fibonacci, em que cada número representa a soma dos dois números anteriores.

A sequência começa com:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, ...

Isto é feito no seguinte programa da regra de fibonacci:

package mainimport “fmt”func main( ) {

result := 0

for i:=0; i <= 10; i++ { result = fibonacci(i) fmt.Printf(“fibonacci(%d) is: %d\n”, i, result)

}}func fibonacci(n int) (res int) { if n <= 1 {

res = 1 } else {

Page 262: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

res = fibonacci(n-1) + fibonacci(n-2) }

return}

Saída:Fibonacci (0) é 1Fibonacci (1) é 1Fibonacci (2) é 2Fibonacci (3) é 3Fibonacci (4) é 5Fibonacci (5) é 8Fibonacci (6) é 13Fibonacci (7) é 21Fibonacci (8) é 34Fibonacci (9) é 55Fibonacci (10) é 89

Muitos problemas têm uma solução recursiva elegante, como o famoso algoritmo Quicksort.Um problema importante quando se utiliza funções recursivas é estouro de pilha: isso pode ocorrer

quando são necessários um grande número de chamadas recursivas e os programas ficar sem memória pilha alocada. Isso pode ser resolvido usando uma técnica chamada avaliação preguiçosa, implementado em Go com um canal e um goroutine. Exercício anterior resolve o problema de Fibonacci desta maneira.

Funções mutuamente recursivas também pode ser usado em Go: estas são as funções que requerem uma outra. Devido ao processo de compilação Go, estas funções podem ser declaradas em qualquer ordem. Aqui está um exemplo simples: mesmo chama de estranho, e até mesmo as chamadas estranhas.

package mainimport (“fmt”)func main( ) { fmt.Printf(“%d is even: is %t\n”, 16, even(16)) / / 16 é mesmo: é verdade fmt.Printf(“%d is odd: is %t\n”, 17, odd(17)) / / 17 é estranho: é verdade fmt.Printf(“%d is odd: is %t\n”, 18, odd(18)) / / 18 é estranho: é falsa}func even(nr int) bool { if nr == 0 {return true} return odd(RevSign(nr)-1)}func odd(nr int) bool { if nr == 0 {return false} return even(RevSign(nr)-1)}func RevSign(nr int) int { if nr < 0 {return -nr} return nr}

Funções como parâmetros

As funções podem ser usadas como parâmetros em uma outra função, a função passada pode, então, ser chamado de dentro do corpo dessa função, é por isso que é comumente chamado de callback. Para ilustrar aqui é um exemplo simples:

Page 263: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport ( “fmt”)func main( ) { callback(1, Add)}func Add(a,b int) { fmt.Printf(“The sum of %d and %d is: %d\n”, a, b, a + b)}func callback(y int, f func(int, int)) { f(y, 2) / / Isso se torna Adicionar (1, 2)}

/ / saida: The sum of 1 and 2 is: 3

Um bom exemplo do uso de uma função de um parâmetro é a função strings.IndexFunc ( ):Ele tem a função de assinatura IndexFunc (s string, f func(c int) bool) e int retorna o índice em s do

primeiro caractere Unicode para o qual f (c) é verdadeiroa, ou -1 se nenhum o fizer.Por exemplo strings.IndexFunc (linha, unicode.IsSpace) Irá retornar o índice do caractere espaço em

branco primeiro na linha. Claro que você pode fazer a sua própria função f, por exemplo:

func IsAscii(c int) bool { if c > 255 { return false

}return true

}

Depois vamos discutir um exemplo de uma função que tem uma outra função como um parâmetro, no contexto de escrever um programa de cliente-servidor:

type binOp func(a, b int) intfunc run(op binOp, req *Request) { ... }

Closures (literais de função)

Às vezes nós não queremos dar uma função de um nome, então vamos fazer uma função anônima (também conhecido sob os nomes de uma função lambda, uma função literal, ou um fecho), por exemplo: func (x,y int) int {return x + y}

Essa função não pode ficar por conta própria (o compilador dá o erro: declaração de não declaração corpo da função fora), mas pode ser atribuído a uma variável, que é uma referência a essa função:

fplus := func(x, y int) int { return x + y }

Em seguida, invocada como se fplus era o nome da função: fplus(3,4)Ou ele pode ser chamado diretamente: func(x, y int) int { return x + y } (3, 4)

Aqui está uma chamada para uma função lambda, que calcula a soma de inteiros flutua até 1 milhão, gofmt reformata uma função lambda, desta forma:

func ( ) { sum = 0,0 for i := 1; i <= 1E6; i + + { sum += i }} ( )

Page 264: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

O primeiro ( ) é a lista de parâmetros e segue imediatamente após a palavra-chave função porque não há nenhuma função de nome. O { } compõem o corpo da função, e último par de ( ) representam a chamada da função.

Aqui está um exemplo de atribuí-la a uma variável, g no seguinte trecho (function_literal.go), que é, em seguida, do tipo de função:

package mainimport “fmt”func main( ) { f( )}func f( ) { for i := 0; i < 4; i++ { g := func(i int) { fmt.Printf(“%d “, i) } g(i) fmt.Printf(“ - g is of type %T and has value %v\n”, g, g) }}

Saída:

0 - g é do tipo func (int) e tem valor 0x681a801 - g é do tipo func (int) e tem valor 0x681b002 - g é do tipo func (int) e tem valor 0x681ac03 - g é do tipo func (int) e tem valor 0x681400

Vemos que o tipo de g é func (int), o seu valor é um endereço de memória.Portanto, neste atribuição temos, de fato, uma variável com um valor de função: funções lambda

podem ser atribuídas a variáveis e tratados como valores.

Aplicação de fechamento: a função que retorna outra função

Em function_return.go programa vemos funções Add2 e Adder que retornar outra função func lambda (b int) int:

func Add2( ) (func(b int) int)func Adder(a int) (func(b int) int)

Add2 não tem parâmetros, mas Adder leva um int como parâmetro.

Nós podemos fazer casos especiais de Adder e dar-lhes um nome.

package mainimport “fmt”função main ( ) { / /make uma função Add2, dar-lhe um nome p2, e chamo: p2: = Add2 ( ) fmt.Printf ("Call Add2 por 3 dá:% v \ n", p2 (3)) / / make uma função especial Adder, um valor 3 recebe: TwoAdder: = Adder (2) fmt.Printf (“The result is: %v\n”, TwoAdder(3))}func Add32 ( ) (func (b int) int) { return func(b int) int { return b + 2 }}func Adder(a int) (func(b int) int) {

Page 265: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

return func(b int) int { return a + b }}

/ * Saída:

Call Add2 for 3 gives: 5The result is: 5* /

Aqui é (quase) a mesma função utilizada de um modo ligeiramente diferente:

package mainimport “fmt”func main( ) { var f = Adder( ) fmt.Print(f(1),” - “) fmt.Print(f(20),” - “) fmt.Print(f(300))}func Adder( ) func(int) int { var x int return func(delta int) int { x += delta return x }}

Adder ( ) agora é atribuído a variável f (o qual é, em seguida, do tipo de função (int) int)

A saída é: 1 - 21-321

Nas chamadas para f, delta no adicionador ( ) recebe, respectivamente, os valores de 1, 20 e 300.Nós vemos que entre chamadas de f o valor de x é retido, por um lado é 0 + 1 = 1, então torna-se 1 +

20 = 21, então 21 é adicionado a 300 para dar o resultado 321: as lojas de função lambda e acumula os valores de suas variáveis: ele ainda tem acesso às variáveis (locais) definidas na função atual.

Essas variáveis locais também podem ser parâmetros, como Adder (a int).Isto demonstra claramente que funções literais em Go são encerramentos.As variáveis que a função lambda usa ou atualizações também podem ser declaradas fora do lambda,

como neste trecho:

var g intgo func (int i) { s := 0 for j: = 0, j <i, j + + + = {s} j g = s} (1000) / / Passa argumento 1.000 para a função de literal.

A função de lambda pode ser aplicada a todos os elementos de um conjunto, actualizando estas variáveis. Em seguida, essas variáveis podem ser usadas para representar ou calcular valores ou médias globais.

Debugando Closures

Em ciência da computação e na programação uma clausura é uma função que referencia variáveis livres no contexto léxico. Uma clausura ocorre normalmente quando uma função é declarada dentro do corpo de

Page 266: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

outra, e a função interior referência variáveis locais da função exterior. Em tempo de execução, quando a função exterior é executada, então uma clausura é formada, que consiste do código da função interior e referências para quaisquer variáveis no âmbito da função exterior que a clausura necessita. As clausuras são utilizadas para:

Bibliotecas de software podem permitir que os usuários customizem o comportamento passando clausuras como argumentos às funções importantes. Por exemplo, uma função que classifique valores pode aceitar um argumento de clausura que compare os valores a ser classificados de acordo com um critério definido pelo próprio usuário.

As funções múltiplas podem ser produzidas num mesmo ambiente, permitindo-as de se comunicar confidencialmente.

Sistemas de objetos podem ser construídos com clausuras. Por exemplo, Scheme padrão não suporta programação orientada a objetos, mas há sistemas de objetos construídos para essa linguagem de programação com recurso a clausuras.

Às vezes nós não queremos dar uma função de um nome , então vamos fazer uma função anônima (também conhecido sob os nomes de uma função lambda , uma função literal , ou um fecho ).Go suporta funções anônimas e encerramentos e suas declarando funções anônimas são muito leves. O apoio da Go para funções anônimas é mais uma reminiscência do apoio função anônima em JavaScript, mas não é o tipo frágil de apoio função anônima que você começa com lambdas do Python (uma declaração somente) ou situação de Ruby, onde existem várias maneiras para criar fechamentos.Um Closure é uma função que "captura " todas as constantes e variáveis que são apresentar , no mesmo âmbito , onde ele é criado , se ele se refere a eles. este meios que o fechamento é capaz de acessar tais constantes e variáveis , quando o fechamento é chamada , mesmo se ele for chamado longe do local onde ele foi criado. Não faz importa se quaisquer constantes ou variáveis capturadas ter saído do alcance tão longo como um fecho que se refere a eles sejam mantidos vivos durante o fecho de usar .No Go, cada função anônima (ou função literal , como são chamados no Go especificação ) é um encerramento .Um fechamento é criado usando quase a mesma sintaxe de uma função normal,mas com uma diferença fundamental : O fechamento não tem nome (de modo a palavra-chave é função imediatamente seguido por um parêntese de abertura ) . Para fazer uso de um nós fechamento normalmente atribuí-lo a uma variável ou colocá-lo em uma estrutura de dados (como um mapa ou slice ) .A palavra-chave de defer é muitas vezes usado com uma função lambda. Ele pode , então, também alterar valores de retorno , desde que você está usando parâmetros de resultado nomeados. Funções lambda também pode ser lançado como um goroutine com go.Funções lambda são também chamados de fechamentos (um termo da teoria das linguagens funcionais) : eles podem se referir a variáveis definidas em uma função circundanteOutra forma de formular este é : um fecho no escopo da função em que é declarada. Esse estado é então dividido entre a função circundante e do encerramento , e as variáveis de sobreviver, enquanto eles são acessíveis. Na prática, quando queremos criar muitas funções semelhantes, ao invés de fazer com que cada um, individualmente, muitas vezes usamos uma função que retorna uma função. Aqui está uma função que retorna fábrica funções que adicionam um sufixo a um nome de arquivo, Äîbut somente se o isn sufixo, AOT já está presente.Tipos de função no Go também pode ter métodos. Há dois efeitos colaterais para o fato de que tipos de função podem ter métodos em Go: em primeiro lugar, uma vez que qualquer tipo que pode ter métodos podem satisfazer uma interface, tipos de função em Go também pode ser encaixotado em tipos de interface válidos. Em segundo lugar, uma vez que os métodos em GO pode ter ou ponteiro ou valor receptores, podemos usar métodos em função ponteiros para mudar a função que está sendo apontado na chamada do método contexto.

Uma função que pode retornar outra função e uma função que tem uma outra função como um parâmetro são chamadas de funções de ordem superior, o que é uma característica da categoria de linguagens chamadas linguagens funcionais. Vimos que funciona também são valores, por isso é claro que Go possui algumas das principais características de uma linguagem funcional. Closures são usados com frequência em Go, muitas vezes em combinação com goroutines e canais.

Ao analisar e depurar programas complexos com milhares de funções em diferentes códigos-arquivos chamando um ao outro, que muitas vezes pode ser útil saber em determinados pontos no programa o arquivo que está sendo executado e número da linha na mesma. Isso pode ser feito usando as funções especiais do runtime pacotes ou log. No pacote de tempo de execução do Caller function ( ) fornece essas informações, de modo que um fechamento onde ( ) poderia ser definido o que exige isso, e, em seguida, ser invocado sempre que necessário:

where( ) := func ( ) {

Page 267: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

_, file, line, _ := runtime.Caller(1) log.Printf(“%s:%d”, file, line)}where( )/ / Algum códigowhere( )/ / Um pouco mais de códigowhere( )

O mesmo pode ser conseguido através da criação de uma flag no pacote de log:

log.SetFlags (log.Llongfile)log.Print ("")

ou se você gosta da brevidade do "onde":

var where = log.Printfunc func1( ) {where( )… algum códigowhere( )… algum códigowhere( )}

O tempo de uma função

Às vezes, é interessante saber quanto tempo um determinado cálculo levou, por exemplo, para comparar e benchmarking cálculos. Uma maneira simples é registrar o tempo de início antes do cálculo, e tempo do fim após o cálculo usando a função Now ( ) do pacote de tempo, era diferença entre eles pode ser calculada com Sub ( ). No coding, isso é assim:

start := time.Now( )longCalculation( )end := time.Now( )delta := end.Sub(start)fmt.Printf(“longCalculation took this amount of time: %s\n”, delta)

Se você tem otimizado um pedaço de código sempre tempo a versão anterior era versão otimizada para ver que não é um (o suficiente) vantagem significativa; no seguinte § vemos uma otimização aplicada que é certamente vale a pena.

Usando memoization para o desempenho

Ao fazer cálculos pesados uma coisa que pode ser feito para aumentar o desempenho é não repetir qualquer cálculo que já foi feito e que devem ser reutilizadas. Em vez cache o valor calculado na memória, que é chamado memoization. Um grande exemplo disso é o programa de Fibonacci:

Para calcular o número de Fibonacci n-th, você precisa das duas precedentes, que normalmente já foram calculados. Se você não estocar os resultados anteriores, a cada mais elevados de Fibonacci número resulta em uma avalanche cada vez maior de novos cálculos, o que é precisamente o que a versão da fibonnaci.go faz.

Estoque simples do número de Fibonacci n-th em uma array no índice n, e antes de calcular um Fibonnaci-número, procure primeiro na array, se ainda não foi calculado.

Este princípio é aplicado na fibonacci_memoization.go. O ganho de desempenho é surpreendente, tempo ambos os programas para o cálculo até o número Fibonnaci 40º:

Page 268: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Normalmente (fibonacci.go): o cálculo leva essa quantidade de tempo: 4,730270 s com memoization: o cálculo levou essa quantidade de tempo: 0.001000 s

Neste algoritmo memoization é óbvio, mas que muitas vezes pode ser aplicado em outros cálculos, bem como, talvez, através de mapas ao invés de arrays ou slices.

Fibonacci_memoization.go:

package mainimport (

“fmt” “time”

)const LIM = 41var fibs [LIM]uint64func main( ) {

var result uint64 = 0 start := time.Now( ) for i:=0; i < LIM; i++ {

result = fibonacci(i) fmt.Printf(“fibonacci(%d) is: %d\n”, i, result)

} end := time.Now( ) delta := end.Sub(start) fmt.Printf(“longCalculation took this amount of time: %s\n”, delta)

}func fibonacci(n int) (res uint64) { / / Memoization: verificar se Fibonacci (n), já é conhecido na array:if fibs[n] != 0 {

res = fibs[n] return

} if n <= 1 { res = 1

} else {

res = fibonacci(n-1) + fibonacci(n-2) } fibs[n] = res return

}

Memoização é útil para funções relativamente caros (não necessariamente recursiva como no exemplo) que são chamados lotes de vezes com os mesmos argumentos. Ele também pode ser aplicado apenas às funções puras, estas são funções que produzem sempre o mesmo resultado com os mesmos argumentos, e não tem efeitos secundários.

Arrays e slices

Neste capítulo vamos começar com a avaliar estruturas de dados que contêm uma série de itens, os chamados coleções, como arrays (slices) e mapas. Aqui, a influência Python é óbvio.

O tipo de array, indicado pelo [ ], a notação é bem conhecida em quase todas as linguagens de programação como o carro-chefe básica em aplicações. Uma array Go é praticamente o mesmo, mas tem algumas peculiaridades. Não é tão dinâmico como em C, mas para isso Go tem o tipo de slice. Esta é uma abstração construída em cima do tipo array de Go, e assim entender slices devemos primeiro entender arrays. Arrays têm o seu lugar, mas eles são um pouco inflexível, para que você não vê-los muitas vezes em código Go. Slices, porém, estão em toda parte. Apoiam-se Arrays para fornecer grande poder e conveniência.

Page 269: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Declaração e inicialização

Uma é um numerado e sequência de comprimento fixo de itens de dados (elementos) do mesmo tipo simples (que é uma estrutura de dados homogêneos), este tipo pode ser qualquer coisa a partir de tipos primitivos como inteiros, strings para os tipos de auto definido. O comprimento deve ser uma expressão constante, que deve ser avaliada como um valor inteiro não negativo. Faz parte do tipo de array, assim como arrays declarados [5] int e [10] int diferem no tipo. A inicialização de uma Array com valores conhecidos em tempo de compilação é feito com literais de array. O número de elementos é chamada o comprimento e nunca é negativo.

ArrayType = "[" ArrayLength "]" ElementType .ArrayLength = Expression .ElementType = Type .

Observação:Se queremos o tipo de item pode ser qualquer tipo, usando a interface vazia como tipo. Ao usar os

valores que primeiro teria que fazer uma declaração de tipo.Os itens podem ser acessados (e alterados) através de seu índice (a posição), o índice começa a partir

de 0, de modo que o primeiro elemento tem índice 0, o segundo índice 1, etc. (Arrays são baseadas em zero, como de costume no família de línguas C). O número de itens, também chamada de len ou tamanho da array de comprimento, é fixo e deve ser dada ao declarar o array (len tem de ser determinado em tempo de compilação, a fim de alocar a memória), o comprimento máximo de array é de 2 Gb .

O formato da declaração é:

var identifier [len]type

Por exemplo: var arr1 [5]int

Cada compartimento contém um inteiro, quando declarar uma array, cada item é automaticamente inicializado com o valor de zero padrão do tipo, aqui todos os itens padrão para 0.

O comprimento de arr1 len (arr1) é 5, e o índice varia de 0 a len(arr1) -1.O primeiro elemento é dada pela arr1 [0], o terceiro elemento é dada pela arr1[2], em geral, o elemento

de índice i é dada por arr1[i]. O último elemento é dada por: arr1 [len (arr1) -1]Atribuir um valor a uma array de item no índice i é feito por: arr[i] = Valor, assim Arrays são mutáveis.Somente índices válidos pode ser ser usado. Quando se utiliza um índice igual ou superior a len (arr1):

se o compilador pode detectar isso, o índice de mensagens fora dos limites é dada, mas caso contrário, o código compila muito bem e executar o programa vai dar o panic:

Erro de execução: índice fora do intervalo.Por causa do índice, uma maneira natural de loop sobre uma array é usar o para-construção:

• para inicializar os itens da Array• para imprimir os valores, ou, em geral:• para procissão cada item em sucessão.

Um exemplo básico:

package mainimport “fmt”func main( ) {

var arr1 [5]int for i:=0; i < len(arr1); i++ {

arr1[i] = i * 2 } for i:=0; i < len(arr1); i++ { fmt.Printf(“Array at index %d is %d\n”, i, arr1[i])

Page 270: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}}

Saída:

Array no índice 0 é 0Array no índice 1 é 2Array no índice 2 é 4Array no índice 3 é de 6Array no índice 4 é de 8

Muito importante aqui é a condição do loop for: i <= len (arr1)

i <= len(arr1) daria um índice fora da faixa de erros.

IDIOMA:

<Len (arr1)for i: = 0; i <len (arr1); i + + {arr1 [i] = ...}A construção de-gama também é útil:

IDIOMA:

for i:= range arr1 {...}

Aqui eu também é o índice na Array. Tanto para-construções também trabalhar para slices, é claro.

Uma array em Go é um tipo de valor (e não um ponteiro para o primeiro elemento como em C / C + +), para que ele possa ser criado com new( ): var arr1 = new ([5] int)

Qual é a diferença com: var arr2 [5] int? arr1 é do tipo *[5] int, arr2 é do tipo [5] int. A consequência é que, quando a atribuição de uma array para outra, uma cópia distinta na memória da array é feita. Por exemplo, quando:

arr2 := arr1arr2[2] = 100

Em seguida, as arrays têm valores diferentes, mudando arr2 após a atribuição não muda arr1.Assim, quando uma array é passada como um argumento para uma função como em func1 (arr1), uma

cópia da array é feita, e func1 não pode mudar o arr1 array original.Se você quer que isso seja possível, ou você quer uma solução mais eficiente, então arr1 devem ser

passados por referência com o & operador, como no func1 (& arr1), como no exemplo a seguir:

package mainimport “fmt”func f(a [3]int) { fmt.Println(a) }func fp(a *[3]int) { fmt.Println(a) }func main( ) { var ar [3]intf(ar) / / Passa uma cópia do arfp(&ar) / / passa um ponteiro para ar}

Saída: [0 0 0]& [0 0 0]

Page 271: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Outra forma equivalente é fazer com que uma slice da array e passar isso para a função.

literais de array

Quando os valores (ou alguns deles) dos itens são conhecidos de antemão, existe uma inicialização mais simples usando o {,,} notação chamado literais de array (ou construtores), em vez de inicializar todos os itens do [ ] = caminho. (Todos os tipos compostos têm uma sintaxe semelhante para a criação de valores literais).

package mainimport “fmt”func main( ) { var arrAge = [5]int{18, 20, 15, 22, 16} var arrLazy = [...]int{5, 6, 7, 8, 22} / / var arrLazy = [ ]int{5, 6, 7, 8, 22} var arrKeyValue = [5]string{3: “Chris”, 4: “Ron”} / /var arrKeyValue = [ ]string{3: “Chris”, 4: “Ron”} for i := 0; i < len(arrKeyValue); i++ { fmt.Printf(“Person at %d is %s\n”, i, arrKeyValue[i]) }}

1 variante: var arrage = [5] int {18, 20, 15, 22, 16}Note-se que a [5] int podem ser omitidos a partir do lado da mão esquerda[10] int {1, 2, 3}: este é um array de 10 elementos com o 1º, três diferente de 0.

Segunda variante: var arrLazy = [...] int {5, 6, 7, 8, 22}… indica o compilador tem de contar o número de itens a obter o comprimento da Array.Mas [...] int não é um tipo, então isso é ilegal: var arrLazy [...] int = [...] int {5, 6, 7, 8, 22}O … também pode ser omitido (tecnicamente falando torna-se então uma slice).

3 ª variante: chave: sintaxe valor: var arrKeyValue = [5] string {3: "Chris", 4: "Ron"}Apenas os itens com índices (chaves) 3 e 4 de obter um valor real, os outros estão definidos para

strings vazias, como é mostrado na saída:

Person at 0 isPerson at 1 isPerson at 2 isPerson at 3 is ChrisPerson at 4 is Ron

Aqui também o comprimento pode ser escrito como … ou mesmo ser omitida.Você pode obter o endereço de uma array literal para obter um ponteiro para uma instância recém-

criada, consulte Listagem

package mainimport “fmt”func fp(a *[3]int) { fmt.Println(a) }func main( ) { for i := 0; i < 3; i++ { fp(&[3]int{i, i * i, i * i * i}) }}

Saída: & [0 0 0] & [1 1 1]

Page 272: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

& [2 4 8]Pontos geométricos (ou vetores matemáticos) são um exemplo clássico do uso de arrays. Para

esclarecer o código muitas vezes um alias é utilizado: type Vector3D [3] float32 var vec Vector3D

Arrays multidimensionais

As arrays são sempre de 1-dimensional, mas podem ser compostos para formar Arrays multidimensionais, como: [3] [5] int

[2] [2] [2] float64

As Arrays interiores têm sempre o mesmo comprimento. Arrays multidimensionais da Go são retangulares (as únicas exceções podem ser arrays de slices (slices).

package mainconst ( WIDTH =1920 HEIGHT = 1080)type pixel intvar screen [WIDTH][HEIGHT]pixelfunc main( ) { for y := 0; y < HEIGHT; y++ { for x := 0; x < WIDTH; x++ { screen[x][y] = 0 } }}

Passando uma array para uma função

Passando arrays grandes para uma função rapidamente consome muita memória.

Existem 2 soluções para evitar isso:

1 - Passe um ponteiro para a array2 - Use uma slice da array

O exemplo a seguir Listagem

package mainimport “fmt”func main( ) {

array := [3]float64{7.0, 8.5, 9.1} x := Sum(&array) / / Note a explícita operador de endereço

/ / Passar um ponteiro para a array fmt.Printf(“The sum of the array is: %f”, x)

}

func Sum(a *[3]float64) (sum float64) { for _, v := range a { / / Dereferencing * a voltar para a Array não é necessário!

sum += v

/ / saída: A soma da Array é: 24.600000

Page 273: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Slices (Slices)

Uma slice é uma referência a um segmento contíguo (seção) de uma array (que chamaremos a array subjacente, e que normalmente é anônimo), então uma slice é um tipo de referência (portanto, mais parecido com o tipo de array em C / C + + , ou o tipo de lista em Python). Esta secção pode ser toda a array, ou de um subconjunto dos itens indicados por um início e um índice estreitol (o item no índice estreitol não está incluído na slice).

Slices fornecer uma janela dinâmica para a array subjacente.As slices são intercambiáveis e têm um comprimento determinado pelo len ( )-função.A slice índice de um determinado artirá pode ser menor do que o índice de um mesmo elemento da

array subjacente. Ao contrário de uma array, o comprimento de uma slice pode alterar durante a execução do código, minimamente 0 e no máximo o comprimento da array subjacente: uma slice é array de comprimento variável.

A tampa função capacidade embutida ( ) de uma slice é uma medida de quanto tempo uma slice pode tornar-se: é o comprimento da slice + o comprimento da array para além da slice. Se s é um tampão de slice é o tamanho da array de s [0] para o estreitol da array. Comprimento de uma slice nunca pode exceder a sua capacidade, de modo a seguinte assertion é sempre verdadeiroa para uma slice s: 0 <= len (s) <= cap (s)

Várias slices podem compartilhar dados se representam peças do mesmo array; várias arrays nunca podem compartilhar dados. Portanto, uma slice partes de armazenamento com sua array subjacente e com outras slices da mesma array, pelo contrário arrays distintas sempre representam armazenamento distinta. Arrays são em blocos de construção de fatos para slices.

Vantagem:

Porque slices são referências, eles não usam a memória adicional e por isso são mais eficientes de usar do que as arrays, por isso eles são usados muito mais do que as arrays em Go-código.

O formato da declaração é: var identifier [ ]type não há necessidade de comprimento.Uma slice que ainda não foi inicializado está definido para zero por padrão, e tem comprimento 0.Formato de inicialização de uma slice: var slice1 [ ]type = arr1[start:end]Isto representa o sub array de arr1 composto dos itens do início índice para o índice estreitol de 1.So

slice1 [0] == arr1 [start] é uma assertion verdadeiroa.Esta pode ser definida antes mesmo da arr1 array é preenchida.Se alguém escreve: var slice1 [ ] type = arr1 [:] então slice1 é igual ao arr1 gama completa (por isso é

um atalho para arr1 [0: len (arr1)]). Outra maneira de escrever isso é: &arr1.Arr1[2]: a última é o mesmo que arr1 [2: len (arr1)] para que contém todos os itens da array da 2 ª até

posterGomente.arr1 [00:03], contendo uma arr1[0:3] array-itens do 1 º até (não incluindo) o Se você precisa cortar o

último elemento de slice1, use: slice1 = slice1 [: len (slice1) -1]Uma slice da array com os elementos 1,2 e 3 podem ser feitas como se segue: s := [3]int{1,2,3}[ : ou s := [...] Int {1,2,3} [:] ou até mesmo s mais curtos: = [ ] int {1,2,3}s2 := [:] é uma slice feito de uma slice, tendo elementos idênticos, mas ainda se refere a mesma array

subjacente.Uma slice s pode ser expandido para seu tamanho máximo com: s = S [: cap (s)],qualquer maior dá um

erro em tempo de execuçãoPara cada slice (também para strings) o seguinte é sempre verdadeiroo:

s == s [: i] + s [i:] / / i é um int: 0 <= i <= len (s)len (s) <= cap (s)

Slices também podem ser inicializados como arrays: var x = [ ] int {2, 3, 5, 7, 11}O que isso faz é criar uma array de comprimento 5 e, em seguida, criar uma slice para se referir a ele.Uma slice de memória é de fato uma estrutura com três domínios: um ponteiro para a array

subjacente, o comprimento da slice, e a capacidade da slice. Isto é ilustrado na figura a seguir, onde a slice y é de comprimento e 2 a capacidade 4.

y [0] = 3 e y [1] = 5. A slice y [00:04] contém os elementos 3, 5, 7 e 11.

Page 274: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport “fmt”func main( ) {

var arr1 [6]int var slice1 [ ]int = arr1[2:5] / / item no índice 5 não incluído!

/ / Carregar a array com números inteiros: 0,1,2,3,4,5 for i := 0; i < len(arr1); i++ {

arr1[i] = i } / / Imprimir a slice: for i := 0; i < len(slice1); i++ { fmt.Printf(“Slice at %d is %d\n”, i, slice1[i]) } fmt.Printf(“The length of arr1 is %d\n”, len(arr1)) fmt.Printf(“The length of slice1 is %d\n”, len(slice1)) fmt.Printf(“The capacity of slice1 is %d\n”, cap(slice1))

/ / Crescer a slice:

slice1 = slice1[0:4] for i := 0; i < len(slice1); i++ { fmt.Printf(“Slice at %d is %d\n”, i, slice1[i]) } fmt.Printf(“The length of slice1 is %d\n”, len(slice1)) fmt.Printf(“The capacity of slice1 is %d\n”, cap(slice1))

/ / Crescer a slice além da capacidade:/ / = Slice1 slice1 [00:07] / / panic: erro de tempo de execução: slice limites fora da faixa}

Saída:

Slice de 0 a 2Slice de 1 a 3Slice de 2 a 4O comprimento é de 6 arr1O comprimento é de 3 slice1A capacidade de slice1 é 4Slice de 0 a 2Slice de 1 a 3Slice de 2 a 4Slice de 3 a 5O comprimento é de 4 slice1A capacidade de slice1 é 4

Se s2 é uma slice, em seguida, você pode mover a slice para a frente por um com s2 s2 = [1:], mas o fim não é movido. Slices só podem avançar: s2 s2 = [-1:] resulta em um erro de compilação.

Slices não pode ser re-cortado abaixo de zero para acessar os elementos anteriores na array(Array).

!! Nunca use um ponteiro para uma slice. Uma slice já é um tipo de referência, por isso é um ponteiro!!

Passando uma slice para uma função

Se você tem uma função que deve operar em uma array, provavelmente você sempre quer declarar o parâmetro formal para ser um slice. Quando você chamar a função, a slice de array para criar (de forma

Page 275: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

eficiente) uma referência slice e passar essa. Por exemplo, aqui é uma função que some todos os elementos de uma array:

func sum(a [ ]int) int { s := 0 for i := 0; i < len(a); i++ { s += a[i]}return s

}func main {

var arr = [5]int{0,1,2,3,4}sum(arr[:])

}

Criação de uma Slice com make( )

Muitas vezes, a array subjacente ainda não está definido, podemos então fazer a slice em conjunto com a array usando o make function ( ): var slice1 [ ]type = make([ ]type, len)

Que pode ser abreviado para: slice1 := make([ ]type, len)Onde len é o comprimento da Array e também o comprimento inicial da slice.Assim, para o s2 slice feito com: s2 := make([ ]int, 10)O seguinte é verdadeiroo: tampa (s2) == len (s2) == 10make leva 2 parâmetros: o tipo a ser criados, bem como o número de itens na slice.Se você quiser slice1 para não ocupar todo o conjunto (com tampa de comprimento), desde o início,

mas apenas um número len de itens, use o formulário: slice1 := make([ ]type, len, cap)make tem a assinatura: make([ ]T, len, cap) [ ] T com tampa de parâmetro opcional.

Então, as seguintes afirmações resultam na mesma slice:make([ ]int, 50, 100)new([100]int)[0:50]

Exemplo:

package mainimport “fmt”func main( ) { var slice1 [ ]int = make([ ]int, 10) / / Carregar a array / slice: for i := 0; i < len(slice1); i++ { slice1[i] = 5 * i } / / Imprimir a slice: for i := 0; i < len(slice1); i++ { fmt.Printf(“Slice at %d is %d\n”, i, slice1[i]) } fmt.Printf(“\nThe length of slice1 is %d\n”, len(slice1)) fmt.Printf(“The capacity of slice1 is %d\n”, cap(slice1))}

Saída:

Slice at 0 is 0Slice at 1 is 5Slice at 2 is 10Slice at 3 is 15Slice at 4 is 20Slice at 5 is 25

Page 276: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Slice at 6 is 30Slice at 7 is 35Slice at 8 is 40Slice at 9 is 45O comprimento é de 10 slice1A capacidade é de 10 de slice1

Diferença entre new( ) e make( )

Esta é muitas vezes confusa à primeira vista: ambos alocar memória na pilha, mas eles fazem coisas diferentes e aplicam-se a diferentes tipos.

▪ new(T) aloca armazenamento zerado para um novo item do tipo T e retorna seu endereço, um valor do tipo * T: ele retorna um ponteiro para um valor recém-alocado zero do tipo T, pronto para o uso, que se aplica aos tipos de valor como arrays e estruturas, que é equivalente a & T { }

▪ make(T) retorna um valor inicializado do tipo T, que se aplica apenas aos 3 built-in tipos de referência: slices, mapas e canais. Em outras palavras, new aloca; make inicializa.

Exemplo:

var p *[ ]int = new([ ]int) / / *p == nil; com len e cap 0ou p := new([ ]int)

p: = make ([ ] int, 0) nossa slice é inicializada, mas aqui aponta para uma array vazia.Ambas as declarações não são muito úteis:var v [ ] int = make ([ ] int, 10, 50)ouv: = make ([ ] int, 10, 50)

Isso aloca uma array de 50 ints e cria um v slice com comprimento de 10 e capacidade de 50 aponta para os primeiros 10 elementos do array.

Slices multidimensionais

Como arrays, as slices são sempre de 1-dimensional, mas pode ser composta para construir objetos de dimensões superiores. Com slices de slice (ou arrays de slices), os comprimentos podem variar dinamicamente, então slices multidimensionais do Go pode ser Irregular. Além disso, as slices internas devem ser alocados individualmente (com o make).

O pacote de bytes

Slices de bytes são tão comuns. Go tem um pacote de bytes com funções de manipulação para que tipo de tipo.

É muito semelhante ao pacote de strings. Além disso, contém um tipo de buffer muito útil:

import “bytes”type Buffer struct { ...}

É um buffer de tamanho variável de bytes com métodos Read e Write, porque ler e escreve um número desconhecido de bytes é o melhor feito em buffer.

Um buffer pode ser criado como um valor como em: tampão var bytes.Bufferou como um ponteiro com o novo como em: var r *bytes.Buffer = new(bytes.Buffer)

Page 277: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

ou criado com a função: func NewBuffer(buf [ ]byte) *Buffer

Cria e inicializa um novo buffer usando buf como seu conteúdo inicial, é melhor usar NewBuffer só para ler o buf.

A concatenação (união) de sequências de caracteres usando um buffer:Isso funciona análogo a classe StringBuilder do Java.Faça um buffer, append cada string está nele com o método buffer.WriteString (s), e converter no

estreitol de volta para uma string com buffer.String ( ), como no seguinte trecho de código:

var buffer bytes.Bufferfor { if s, ok := getNextString( ); ok {/ / método getNextString ( ) não mostrado aqui buffer.WriteString(s) } else { break

}}

fmt.Print (buffer.String ( ), "\ n")

Este método é muito mais do que memória e + = eficiente em termos de CPU, especialmente se o número de strings para concatenar é grande.

faixa construção FOR

Esta construção pode ser aplicada a arrays e slices:for ix, value := range slice1 {...}

O primeiro ix valor de retorno é o índice na array ou uma slice, o segundo é o valor em que o índice, pois eles são variáveis locais conhecidos apenas no corpo do para-assertion, assim valor é uma cópia do item slice nesse índice e não pode ser utilizado para modificar o!

package mainimport “fmt”func main( ) { slice1 := make([ ]int, 4) slice1[0] = 1 slice1[1] = 2 slice1[2] = 3 slice1[3] = 4 for ix, value := range slice1 { fmt.Printf(“Slice at %d is: %d\n”, ix, value) }}

Outro Exemplo

seasons := [ ]string{“Spring”,“Summer”,“Autumn”,“Winter”} for ix, season := range seasons { fmt.Printf(“Season %d is: %s\n”, ix, season) } var season string for _, season = range seasons { fmt.Printf(“%s\n”, season)}

Page 278: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

_ Pode ser usada para descartar o índice.Se você só precisa do índice, você pode omitir a segunda variável, como em:

for ix := range seasons { fmt.Printf(“%d “, ix)}/ / Saída: 0 1 2 3

Use esta versão se você deseja modificar épocas [ix]

Para a faixa com slices multidimensionais:

Pode ser conveniente, para escrever o nested loops como a simples contagem das linhas e do número de um valor de array, como:

for row := range screen { for column := range screen[0] { screen[row][column] = 1 }}

Mudando o comprimento das slices

Vimos que uma slice é muitas vezes feita, inicialmente, menor do que a array subjacente, como este:slice1 := make([ ]type, start_length, capacity)Com start_length da slice e a capacidade do comprimento da array subjacente. Isso é útil porque agora

a nossa slice pode crescer até capacidade. A mudança no comprimento da slice é chamado reslicing, que é feito, por exemplo, como:

Onde estreitol é outro índice estreitol (comprimento) do que antes.sl slice1 =slice1[0:end]Redimensionamento de uma slice de 1 pode ser feito da seguinte forma:= Sl [0: len (sl) +1] / / estender comprimento por 1Uma slice pode ser redimensionada até que ocupa todo o conjunto subjacente.

package mainimport “fmt”func main( ) {

slice1 := make([ ]int, 0, 10) / / load the slice, cap(slice1) is 10: for i := 0; i < cap(slice1); i++ {

slice1 = slice1[0:i+1] / / reslice slice1[i] = i fmt.Printf(“The length of slice is %d\n”, len(slice1))

} / / print the slice: for i := 0; i < len(slice1); i++ {

fmt.Printf(“Slice at %d is %d\n”, i, slice1[i]) }}Saída:

The length of slice is 1The length of slice is 2The length of slice is 3The length of slice is 4The length of slice is 5

Page 279: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

The length of slice is 6The length of slice is 7The length of slice is 8The length of slice is 9The length of slice is 10Slice at 0 is 0Slice at 1 is 1Slice at 2 is 2Slice at 3 is 3Slice at 4 is 4Slice at 5 is 5Slice at 6 is 6Slice at 7 is 7Slice at 8 is 8Slice at 9 is 9

Outro exemplo:var ar = [10] int {0,1,2,3,4,5,6,7,8,9}var a = ar [05:07] / / referência a subarray {5,6} - len (a) é 2 e cap(a) é de 5reslicing a: a = [00:04]/ / Ref de subarray {5,6,7,8} - len (a) agora é 4, mas cap (a) ainda é 5.

Copiando e anexando slices

Para aumentar a capacidade de uma slice é preciso criar uma nova maior slice, e copiar o conteúdo da slice original, para ele. O código a seguir ilustra as funções copiar para copiar slice, e acrescentar para acrescentar novos valores a uma slice.

package mainimport “fmt”func main( ) {

sl_from := [ ]int{1,2,3}sl_to := make([ ]int,10)n := copy(sl_to, sl_from)fmt.Println(sl_to)

/ / output: [1 2 3 0 0 0 0 0 0 0]fmt.Printf(“Copied %d elements\n”, n) / / n == 3

sl3 := [ ]int{1,2,3}sl3 = append(sl3, 4, 5, 6)fmt.Println(sl3) / / Saída: [1 2 3 4 5 6]

}

função append (s [ ] T, T x ...) [ ] T

O acréscimo função acrescenta zero ou mais valores para uma slice s e retorna a slice resultante, com o mesmo tipo como s; os valores têm, naturalmente, de ser de tipo idêntico ao do tipo de elemento de T s. Se a capacidade de s não é grande o suficiente para caber os valores adicionais, append aloca um novo suficientemente grande slice, que se encaixa tanto os elementos slice existentes e os valores adicionais. Assim, a slice retornada pode referir-se a uma array de base diferente. A acrescentar sempre bem-sucedida, a menos que o computador ficar sem memória.

Se você quiser append uma slice y a uma slice x, use o seguinte formulário para expandir o segundo argumento para uma lista de argumentos: x = append (x, y ...)

Observação: append (append) é bom para a maioria dos propósitos, no entanto, se você quer controle total sobre o

processo, você pode usar um AppendByte função como esta:

func AppendByte(slice [ ]byte, data ...byte) [ ]byte {

Page 280: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

m := len(slice) n := m + len(data) if n > cap(slice) {/ / se necessário, realocar

/ / Alocar o dobro do que é necessário, para o crescimento futuro. newSlice := make([ ]byte, (n+1)*2)

copy(newSlice, slice)slice = newSlice

}slice = slice[0:n]copy(slice[m:n], data)return slice

}

func copy(dst, src [ ]T) int

As cópias de cópia função cortar elementos do tipo T a partir de uma origem para um src dst destino, substituindo os elementos correspondentes em dst, e retorna o número de elementos copiados. A origem e o destino podem se sobrepor. O número de argumentos copiados é o mínimo de len (src) e len (dst).

Quando src é uma sequência do tipo de elemento é byte. Se você quiser continuar a trabalhar com o src variável, coloque: src = dst após a cópia.

Applying strings, arrays and slices

Vemos que Unicode caracteres levar 2 bytes; alguns personagens pode até ter 3 ou 4 bytes. Se errônea UTF-8 é encontrado, o personagem está definido para U + FFFD e os avanços do índice por um byte. Da mesma forma, a conversão c: = [ ] int (s) é permitido, então cada int contém um código de ponto de Unicode:

cada personagem a partir da string corresponde a um número inteiro, do mesmo modo que a conversão runes pode ser feito com: r: = [ ] Rune (s)

O número de caracteres em uma string s é dada por len ([ ] int (s)), mas utf8.RuneCountInString (s)É mais rápido.A sequência pode ser anexado a uma slice de bytes, como está:

var b [ ]bytevar s stringb = append(b, s...)

A alteração de um caractere em uma string

Strings são imutáveis. Isto significa que quando str denota uma cadeia que str [índice] não pode ser o lado esquerdo de uma atribuição:

str [i] = 'D', onde i é um índice válido dá o erro não é possível atribuir a str [i]Para fazer isso, você primeiro tem que converter a string para um array de bytes, em seguida, uma

série de itens de um determinado índice pode ser alterado, e então a array deve ser convertido de volta para uma nova cadeia.

Por exemplo, altere "hello" para “cello”s:=“hello”c:=[ ]byte(s)c[0]=’c’s2:= string(c) / / S2 == "cello"

Por isso, é claro que String-extrações são muito fáceis com a sintaxe-slice.

função de comparação para arrays de bytes

Page 281: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

A função a seguir Compare retorna um inteiro comparando duas arrays de bytes lexicographically.O resultado é: 0 if a ==b, -1 if a < b, 1 if a > bfunc Compare(a, b[ ]byte) int { for i:=0; i < len(a) && i < len(b); i++ {{ }switch { case a[i] > b[i]: return 1 case a[i] < b[i]: return -1 }}

/ / Strings são iguais, exceto para uma possível caudaswitch {case len(a) < len(b):return -1case len(a) > len(b):return 1}return 0 / / Strings são iguais

pesquisa e classificação slices e arrays

Pesquisa e classificação são operações muito comuns era biblioteca padrão prevê-los no tipo de pacote. Para classificar uma slice de ints, importar o pacote "sort" e simplesmente chamar os Ints função func (a [ ]int) como em sort.Ints(arri), onde arri é a array ou slice a ser classificados em ordem crescente. Para testar se uma array é ordenada, utilize funções IntsAreSorted (a [ ]int) bool, que retorna verdadeiroo ou falso ou não a array é classificada. Da mesma forma para Float64 elementos, você usa a função func Float64s(a [ ]float64) e para função strings func Strings(a [ ]string).

Para procurar um item em uma array ou uma slice, a array deve ser primeiro classificada (a razão é que as funções de pesquisa são implementadas com o algoritmo binário de busca).Em seguida, você pode usar a função func SearchInts(a [ ]int, n int) int, que procura n na slice a e retorna seu índice. E, claro, as funções equivalentes para float64s e strings existem também:

func SearchFloat64s(a [ ]float64, x float64) intfunc SearchStrings(a [ ]string, x string) int

Mais detalhes podem ser encontrados na informação oficial: http:/ /golang.org/pkg/sort/Esta é a forma de utilizar as funções de tipo-package. Posteriormente descobrimos a teoria por trás

disso, e vamos implementar nós mesmos a funcionalidade de classificação, bem como na embalagem.

Simulando operações com append

Agora, temos a peça que faltava que precisávamos para explicar o projeto do append . A assinatura do append é diferente do nosso costume. Esquematicamente, é assim:

func append(slice [ ]T, elements ...T) [ ]T

onde T é um espaço reservado para qualquer tipo. Você não pode realmente escrever uma função em Go onde o tipo T é determinado pelo chamador. É por isso que append é construído em: ele precisa de apoio do compilador

O append faz é acrescentar os elementos para o fim da slice e devolver o resultado. O resultado deve ser devolvido porque, como acontece com a nossa escrita à mão append, a array subjacente pode mudar. Este exemplo simples

Page 282: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

x := [ ]int{1,2,3}x = append(x, 4, 5, 6)fmt.Println(x)

O método de acréscimo é muito versátil e pode ser utilizado para todos os tipos de manipulações:

1) Append uma slice b para uma slice de um já existente: a = append (a, b ...)2) Copie uma slice de um para uma novo slice b: b = make ([ ] T, len (a)) copy(b, a)3) Eliminar o item no índice i: a = append (a [: i], a [i +1:] ...)4) Corte do índice i cultivam j de uma slice: a = append (a [: i], a [j]: ...)5) Estender uma slice com uma nova slice de comprimento j: a = append(a, make([ ]T, j)...)6) Inserir item no índice x i: a = append(a[:i], append([ ]T{x}, a[i:]...)...)7) Coloque um novo comprimento de slice j no índice i: a = append(a[:i], append(make([ ]T, j), a[i:]...)...)8) Coloque uma slice b existente no índice i: a = append(a[:i], append(b, a[i:]...)...)9) Pop elemento mais alto da pilha: x, a = a[len(a)-1], a[:len(a)-1]10) Empurre um elemento x em uma pilha: a = append(a, x)

Assim, para representar uma sequência de elementos redimensionável usar uma slice e a acrescentar-operação.

A slice é muitas vezes chamado de um vetor em um contexto mais matemática. Se isso torna o código mais claro, você pode definir um alias de vetor para o tipo de slice que você precisa.

slices e coleta de lixo

Uma slice aponta para a array subjacente; essa array poderia ser muito maior do que a slice como no exemplo a seguir. Enquanto a slice é referido, a array completa será mantido na memória até que ele já não é referenciado. Ocasionalmente, isso pode fazer com que o programa para armazenar todos os dados na memória quando é necessária apenas uma pequena parte dela.

Exemplo: esta função FindDigits carrega um arquivo para a memória e procura-lo para o primeiro grupo de dígitos numéricos consecutivos, retornando-los como uma nova slice.

var digitRegexp = regexp.MustCompile(“[0-9]+”)func FindDigits(filename string) [ ]byte {

b, _ := ioutil.ReadFile(filename) return digitRegexp.Find(b)

}

Esse código funciona como descrito, mas os retornados [ ] byte pontos em uma array que contém o arquivo inteiro.

Uma vez que a slice de referencia da array original, enquanto a slice é mantida em torno do coletor de lixo não pode libertar a array; poucos bytes úteis do ficheiro de manter todo o conteúdo da memória.

Para corrigir esse problema pode-se copiar os dados interessantes para uma nova slice antes de devolvê-lo:

func FindDigits(filename string) [ ]byte { b, _ := ioutil.ReadFile(filename) b = digitRegexp.Find(b) c := make([ ]byte, len(b)) copy(c, b) return c

}

Page 283: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Maps

Também conhecida como uma array associativa, uma tabela hash ou um dicionário, mapas são usados para pesquisar um valor pelo seu as- chave ciada.

Muitos outros idiomas têm um tipo similar embutido. Por exemplo , Perl tem hashes , Python tem seus dicionários e C + + também tem mapas (como parte das bibliotecas ) . Em Go temos o tipo de mapa . Um mapa pode ser pensado como uma array indexada por strings ( na sua forma mais simples ) . Mapas são um conveniente e poderoso embutido na estrutura de dados que associa os valores de um tipo (o principal), com valores de outro tipo (ou o elemento de valor) A chave pode ser de qualquer tipo para o qual o operador de igualdade é definida, tal como números inteiros , ponto flutuante e números complexos, strings, ponteiros, interfaces (desde que o tipo dinâmico apoia a igualdade), estruturas e arrays. As slices não pode ser usado como chaves de mapa, porque a igualdade não é definido em cima delas.

Mapas são um tipo especial de estrutura de dados: uma coleção desordenada de pares de elementos, em que um elemento do par é a chave, e o outro elemento, associado com a chave, os dados ou é o valor, por conseguinte, eles são também chamados associativo arrays ou dicionários. Eles são ideais para pesquisar valores rápido: dada a chave, o valor correspondente pode ser recuperada rapidamente.

O comprimento do mapa não tem que ser conhecida a declaração : um mapa pode crescer de forma dinâmica .Como as slices, mapas contém referências a uma estrutura de dados subjacente. Se você passar um mapa para uma função que altera o conteúdo do mapa, as mudanças serão visíveis no chamador.

Os mapas podem ser construídos usando a sintaxe literal composto de costume com pares chaves -valor separados por dois pontos, por isso é fácil de construí-los durante a inicialização.

Um mapa é um tipo de referência e declarou, em geral, como:

var map1 map[keytype]valuetypevar map1 map[string]int(Um espaço é permitido entre [KeyType] valuetype, mas gofmt remove essa)

O comprimento do mapa não tem que ser conhecida a declaração: um mapa pode crescer de forma dinâmica. O valor de um mapa não inicializada é nulo. O tipo de chave pode ser qualquer tipo para o qual as operações == e != São definidos, como string, int, float.

Então, arrays, slices e structs não pode ser usado como tipo de chave, mas ponteiros e tipos de interface pode. Uma maneira de usar estruturas como uma chave é proporcionar-lhes um método Hash ( ) Key( ) ou, de modo que uma tecla numérica ou string original pode ser calculada a partir campos da struct.

O tipo de valor pode ser qualquer tipo; usando a interface vazia como tipo , podemos armazenar qualquer valor, mas ao usar esse valor que primeiro teria que fazer uma declaração de tipo .

Mapas são baratos para passar para uma função: 4 bytes em uma máquina de 32 bits, 8 bytes em uma máquina de 64 bits, não importa a quantidade de dados que possuem. Olhando-se um valor em um mapa chave é rápido, muito mais rápido do que uma busca linear, mas ainda em torno de 100x mais lento do que a indexação direto em uma array ou umaslice, por isso, se o desempenho é muito importante para tentar resolver o problema com slices.

Um mapa com os valores da função também pode ser usado como uma estrutura de ramificação: as teclas são usadas para selecionar o ramo que é uma função que é executada.

Se key1 é um valor fundamental do mapa map1, então map1[key1] é o valor associado a key1, assim como a notação de array-index (uma array pode ser considerada como uma simples forma de um mapa, onde as chaves (Keys) são números inteiros a partir de 0).

O valor associado a key1 pode ser definido como val1 através da atribuição: map1 [key1] = val1A atribuição v: = map1[key1] stores em v o valor correspondente ao key1, se key1 não está presente no

mapa, em seguida, torna-se v o valor zero para o tipo de valor de map1.Len Como de costume (map1) dá o número de pares no mapa, que pode crescer ou diminuir, porque

mapa pares podem ser adicionados ou removidos durante a execução.

package mainimport “fmt”a number of maps are shown:func main( ) {

var mapLit map[string]int

Page 284: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

/ /var mapCreated map[string]float32var mapAssigned map[string]intmapLit = map[string]int{“one”: 1, “two”: 2}mapCreated := make(map[string]float32)mapAssigned = mapLitmapCreated[“key1”] = 4.5mapCreated[“key2”] = 3.14159mapAssigned[“two”] = 3fmt.Printf(“Map literal at \“one\” is: %d\n”, mapLit[“one”])fmt.Printf(“Map created at \“key2\” is: %f\n”, mapCreated[“key2”])fmt.Printf(“Map assigned at \“two\” is: %d\n”, mapLit[“two”])fmt.Printf(“Map literal at \“ten\” is: %d\n”, mapLit[“ten”])

}

Saída:

Mapa literal em "um" é: 1Mapa criado em "key2" é: 3,141590Mapa atribuído em "dois" é: 3Mapa literal em "dez" é: 0

mapList ilustra a utilização do mapa literais: um mapa pode ser inicializado com a notação {key1: val1, key2: val2}, como arrays e estruturas.

Os mapas são tipos de referência: a memória é alocada com a função make:Inicialização de um mapa: var map1[keytype]valuetype = make(map[keytype]valuetype)

ou curtu com: map1 := make(map[keytype]valuetype)mapCreated é feita da seguinte maneira: mapCreated := make(map[string]float)o que equivale a: mapCreated := map[string]float{ }

Também é mapAssigned uma referência para o mesmo valor que mapLit, mudando mapAssigned também muda mapLit como mostra a saída do programa.

!! Não use new, use sempre make com mapas !!Observação: Se você por engano atribuir um objeto de referência com new ( ), você recebe um

ponteiro para uma referência nula, o que equivale a declarar uma variável não inicializada e tomando seu endereço:mapCreated := new(map[string]float)

Então nós começamos na declaração: mapCreated[“key1”] = 4.5o erro do compilador: operação inválida: mapCreated ["key1"] (Índice de tipo *map [string] float).

Para demonstrar que o valor pode ser de qualquer tipo, aqui está um exemplo de um mapa que tem uma função ( ) int como seu valor:

package mainimport “fmt”f unc main( ) {

mf := map[int]func( ) int{ 1: func( ) int { return 10 }, 2: func( ) int { return 20 }, 5: func( ) int { return 50 },

} fmt.Println(mf)

}

A saída é: mapa [01:00 x10903be0 05:00 x10903ba0 02:00 x10903bc0]: os inteiros são mapeados para endereços de funções.

Page 285: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

capacidade Mapa

Ao contrário de arrays, mapas dinamicamente crescer para acomodar novos valores-chave que são adicionados, eles não têm tamanho fixo ou máximo. Mas você pode indicar, opcionalmente, um cap capacidade inicial para ver o mapa, como em make(map[keytype]valuetype, cap) ,

por exemplo: map2 := make(map[string]float, 100)Quando o mapa tem crescido a sua capacidade, e um novo valor de chave é adicionada, em seguida,

o tamanho do mapa Irá aumentar automaticamente por 1. Assim, para grandes mapas ou mapas que crescem muito, é melhor para o desempenho para especificar uma capacidade inicial, mesmo que isso só é conhecido aproximadamente.

Aqui está um exemplo mais concreto de um mapa: mapear o nome de uma nota musical à sua frequência em Hz (medição de frequências em Hz para a escala igual-moderada (A4 = 440Hz)):

noteFrequency: = map [string] float32 {"C0": 16.35, "D0": 18.35, "E0": 20,60, "F0": 21,83,"G0": 24,50, "A0": 27.50, "B0": 30.87, "A4": 440}

Slices como valores do mapa

Quando uma chave tem apenas um valor associado, o valor pode ser de um tipo primitivo. E se uma chave corresponde a muitos valores? Por exemplo, quando temos de trabalhar com todos os processos em um Linux, onde um processo pai como chave (processo-id pid é um valor int) pode ter muitos processos filhos (representados como uma slice de inteiros com seus pid de como itens). Isto pode ser elegantemente resolvido definindo o tipo de valor como um int [ ] ou uma slice de outro tipo. Aqui estão alguns exemplos que definem tais mapas:

mp1 := make(map[int][ ]int)mp2 := make(map[int]*[ ]int)

Testando se um item de valor de chave existe em um mapa-Apagar um elemento

Testando a existência de key1 em map1:Vimos val1 = map1 [key1] nos devolve o val1 valor associado key1. Se key1 não existe no mapa, val1

torna-se o valor zero para o tipo do valor.Mas isso é ambíguo: agora não podemos distinguir entre este caso, ou o caso em que key1 existe e

seu valor é o valor de zero! Para testar isso, podemos usar o seguinte formulário vírgula ok: val1,IsPresent = map1 [key1]IsPresent retorna um valor booleano: se key1 existe no map1, val1 Irá conter o valor para key1, e será

verdadeiroa, se key1 não existe no map1, val1 Irá conter o valor zero para o seu tipo, e IsPresent será falso.Se você quiser apenas para verificar se há a presença de uma chave e não se preocupam com o seu

valor, você poderia escrever:_, ok := map1[key1] / / ok == true se key1 está presente, caso contrário, falseOu combinado com um caso:

if _, ok := map1 [Key1]; ok { / / ...}

Apagar um elemento com key1 de map1:Isto é feito com: delete(map1, key1)

Quando key1 não existe esta declaração não produz um erro.

Page 286: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport “fmt”func main( ) {

var value int var isPresent bool map1 := make(map[string]int) map1[“New Delhi”] = 55 map1[“Bejing”] = 20 map1[“Washington”] = 25 value, isPresent = map1[“Bejing”] if isPresent { fmt.Printf(“The value of \“Bejing\” in map1 is: %d\n”, value)

} else { fmt.Println(“map1 does not contain Bejing”) } value, isPresent = map1[“Paris”] fmt.Printf(“Is \“Paris\” in map1 ?: %t\n”, isPresent) fmt.Printf(“Value is: %d\n”, value) / / delete um item: delete(map1, “Washington”) value, isPresent = map1[“Washington”] if isPresent { fmt.Printf(“The value of \“Washington\” in map1 is: %d\n”, value) } else { fmt.Println(“map1 does not contain Washington”) }

}

Saída:

O valor de "Pequim" em mapa1 é: 20É "Paris" em map1: falsaO valor é: 0mapa1 não contém Washington

A para a faixa de construção

Esta construção também pode ser aplicada aos mapas:

for key, value := range map1 { ...}

A primeira chave valor de retorno é a chave do mapa, thwe segundo é o valor para essa chave, pois eles são variáveis locais conhecidos apenas no corpo do para-assertion. O primeiro elemento em um mapa iteração é escolhido random.If você está interessado apenas nos valores, use o formulário:

for _, value := range map1 { ...}

Para obter apenas as chaves, você pode usar:

for key := range map1 { fmt.Printf(“key is: %d\n”, key)}

Page 287: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Exemplo: Listagem

package mainimport “fmt”func main( ) {

map1 := make(map[int]float32) map1[1] = 1.0 map1[2] = 2.0 map1[3] = 3.0 map1[4] = 4.0

for key, value := range map1 {fmt.Printf(“key is: %d - value is: %f\n”, key, value) }}

Saída:chave é: 3 - valor é: 3.000000chave é: 1 - valor é: 1.000000chave é: 4 - valor é: 4.000000chave é: 2 - valor é: 2,000000

Vemos que um mapa não é a chave-ordenada, nem é ordenada pelos valores.

Uma slice de mapas

Suponha que nós queremos fazer uma slice de mapas, então devemos usar make ( ) 2 vezes, primeiro para a slice, em seguida, para cada um dos mapas-elementos da slice .

Mas tome cuidado para usar o mapa-itens da slice pelo índice, como na versão A. O valor do item na versão B é uma cópia do mapa de valor, de modo que os verdadeiroos mapa-variáveis não inicializadas.

package mainimport ( “fmt”)func main( ) {/ / Versão A: items := make([ ]map[int]int, 5)

for i := range items { items[i] = make(map[int]int, 1) items[i][1] = 2

} fmt.Printf(“Version A: Value of items: %v\n”, items)

/ / Versão B: Não é bom! items2 := make([ ]map[int]int, 5)

for _, item := range items2 { item = make(map[int]int, 1

/ / Item é apenas uma cópia do elemento slice.item[1] = 2/ / Este 'item' será perdida na próxima iteração.}fmt.Printf(“Version B: Value of items: %v\n”, items2)}

/ * Saída:

Version A: Value of items: [map[1:2] map[1:2] map[1:2] map[1:2] map[1:2]]Version B: Value of items: [map[ ] map[ ] map[ ] map[ ] map[ ]]* /

Page 288: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Classificando um mapa

Por padrão um mapa isw não ordenados, nem mesmo sobre o valor de suas chaves. Se você quer um mapa ordenado, copiar as chaves (ou valores) para uma slice, ordenar a slice, e, em seguida, imprimir as chaves e / ou valores usando um for-range na slice.

/ / O alfabeto telefone:package mainimport ( “fmt”

“sort”)

)var (

barVal = map[string]int{“alpha”: 34, “bravo”: 56, “charlie”: 23, “delta”: 87, “echo”: 56, “foxtrot”: 12, “golf”: 34, “hotel”: 16, “indio”: 87, “juliet”: 65, “kilo”: 43, “lima”: 98}

)

fmt.Println(“unsorted:”) for k, v := range barVal { fmt.Printf(“Key: %v, Value: %v / “, k, v) } keys := make([ ]string, len(barVal)) i := 0 for k, _ := range barVal {

keys[i] = k i++

} sort.Strings(keys) fmt.Println( ) fmt.Println(“sorted:”) for _, k := range keys { fmt.Printf(“Key: %v, Value: %v / “, k, barVal[k])

}}

/ * Saída:indiferenciados:

Key: indio, Value: 87 / Key: echo, Value: 56 / Key: juliet, Value: 65 / Key: charlie,Value: 23 / Key: hotel, Value: 16 / Key: lima, Value: 98 / Key: bravo, Value: 56 / Key:alpha, Value: 34 / Key: kilo, Value: 43 / Key: delta, Value: 87 / Key: golf, Value: 34 /Key: foxtrot, Value: 12 /

Classificadas:

Key: alpha, Value: 34 / Key: bravo, Value: 56 / Key: charlie, Value: 23 / Key: delta,Value: 87 / Key: echo, Value: 56 / Key: foxtrot, Value: 12 / Key: golf, Value: 34 / Key:hotel, Value: 16 / Key: indio, Value: 87 / Key: juliet, Value: 65 / Key: kilo, Value: 43/ Key: lima, Value: 98 /* /

Mas se o que você quer é uma lista ordenada é melhor você usar uma slice de estruturas, que é mais eficiente:

Page 289: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

type struct { key string value int}

Inversão um mapa

Com isto queremos dizer mudar os valores e as chaves. Se o tipo de valor de um mapa é aceitável como um tipo de chave, e os valores do mapa são únicos, isto pode ser feito facilmente:

package mainimport (

“fmt”)var (

barVal = map[string]int{“alpha”: 34, “bravo”: 56, “charlie”: 23,“delta”: 87, “echo”: 56, “foxtrot”: 12, “golf”: 34, “hotel”: 16,“indio”: 87, “juliet”: 65, “kilo”: 43, “lima”: 98}

)func main( ) {

invMap := make(map[int]string, len(barVal))for k, v := range barVal {

invMap[v] = k} fmt.Println(“inverted:”) for k, v := range invMap { fmt.Printf(“Key: %v, Value: %v / “, k, v)

}}

/ * Saída: invertido:

Key: 12, Value: foxtrot / Key: 16, Value: hotel / Key: 87, Value: delta / Key: 23,Value: charlie /Key: 65, Value: juliet / Key: 43, Value: kilo / Key: 56, Value: bravo / Key: 98,Value: lima /Key: 34, Value: golf /* /

Isso dá errado, claro, quando os itens de valor originais não são únicos e, nesse caso não houver erro, mas o processamento do mapa invertido é simplesmente pararam quando uma tecla não exclusivo é encontrado, e ele provavelmente não Irá conter todos os pares a partir do original mapear! A solução é testar com cuidado para a singularidade e fazendo uso de um mapa de valores múltiplos, neste caso do tipo map[int] [ ]string

Visão geral da biblioteca padrão.

The Go-distribuição contém mais de 150 padrões embutidos pacotes para funcionalidades comuns, como a fmt, os,..., Como um todo, designada como a biblioteca de padrão, para a maior parte (exceto algumas rotinas de nível baixo) construído no próprio Go. Eles estão documentados em: http:/ /golang.org/pkg/

Aqui vamos discutir o seu propósito geral de um número deles agrupados por função, não vamos entrar em detalhes sobre a sua estrutura interna.

Page 290: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

O pacote de regexp.

No programa seguinte que deseja pesquisar um padrão de strings pat em uma string Searchin.

Testando se ocorrer o padrão é fácil, basta usar jogo: ok, _ := regexp.Match(pat, [ ]byte(searchIn))

onde ok vai ser verdadeiroa ou falsa, ou usar matchstring:ok, _ := regexp.MatchString(pat,searchIn)

Para mais funcionalidade, você deve primeiro fazer a (ponteiro para a) objeto Regexp do padrão, o que é feito através da função de compilação. Então nós temos à nossa disposição um número inteiro de match-, localizar e substituir-funções.

Package mainimport (

“fmt” “regexp” “strconv”

)func main( ) { / / String para busca searchIn := “John: 2578.34 William: 4567.23 Steve: 5632.18”

pat := “[0-9]+.[0-9]+” / / Padrão para procurar em Searchin f := func (s string) string { v, _ := strconv.ParseFloat(s, 32) return strconv.FormatFloat(v * 2, ‘f’, 2, 32) } if ok, _ := regexp.Match(pat, [ ]byte(searchIn)); ok { fmt.Println(“Match found!”) } re, _ := regexp.Compile(pat) / / Substituir pat com "# #. #" str := re.ReplaceAllString(searchIn, “##.#”) fmt.Println(str) / / Usando uma função: str2 := re.ReplaceAllStringFunc(searchIn, f) fmt.Println(str2)}/ * Saída:

Match found!John: ##.# William: ##.# Steve: ##.#John: 5156.68 William: 9134.46 Steve: 11264.36* /

A função de compilação também retorna um erro, que temos ignorado aqui com segurança, porque nós entramos no padrão de nós mesmos e saber que é uma expressão regular válida. Se a expressão ser inserido pelo usuário ou tomada de uma fonte de dados, então é necessário verificar este erro de análise.

Neste exemplo, também poderia ter usado o MustCompile função que é como compilação, mas entra em panic quando o padrão não é uma expressão regular válida.

Locking e o pacote de sincronização.

Page 291: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Em programas mais complexos diferentes partes da aplicação podem executar simultaneamente ou concomitantemente, pois isso é tecnicamente chamado, geralmente por meio da execução de cada parte do programa em um segmento diferente do sistema operacional. Quando estas partes diferentes partes e trabalhar com as mesmas variáveis, os problemas mais provável ocorrer: a ordem em que as variáveis são compartilhados atualização não podem ser previstos e, portanto, também os seus valores são imprevisíveis! (Isso é comumente chamado de condição de corrida:a corrida tópicos para as atualizações das variáveis). Este é, naturalmente intolerável em um programa correto, então como é que vamos resolver este problema?

A abordagem clássica é deixar apenas um thread por vez mudar a variável compartilhada: o código em que a variável é alterada (o chamado seção crítica) é bloqueado quando um segmento começa a executar, então nenhuma outra thread pode começar com ele. Somente quando a thread em execução terminar a seção um desbloqueio ocorre, então outro segmento pode acessá-lo.

Em particular, o tipo de mapa que estudamos neste capítulo não contém qualquer bloqueio interno para atingir esse efeito (o que é deixado de fora por razões de performance), é dito que o tipo de mapa não é thread-safe. Então, quando acessos simultâneos acontecer a uma estrutura de dados mapa compartilhado, corrompido, o que significa não correta, os dados do mapa pode resultar.

Em Go este tipo de bloqueio é realizada com a variável Mutex do pacote de sincronização. sync vem sincronizado, aqui ou seja, os fios são sincronizados para atualizar a variável (s) de forma ordenada.

A sync.Mutex é um bloqueio de exclusão mútua: ela serve para proteger a entrada para a seção crítica do código, de modo que apenas um thread pode entrar na seção crítica ao mesmo tempo.

Suponha Informação é uma variável de memória partilhada, que deve ser guardado, em seguida, uma técnica comum é a de incluir um mutex nele, como:

import“sync”type Info struct {

mu sync.Mutex / / … outros campos, como por exemplo

Str string}

Uma função que tem que mudar esta variável poderia, então, ser escrito como:

função Update (informações * Informações) {

func Update(info *Info) { info.mu.Lock( )

/ / Seção crítica: / / Fim da seção crítica info.mu.Unlock( )}

Um exemplo de sua utilidade é um buffer compartilhado, que tem de ser travado antes de atualizar: a

SyncedBuffer: type SyncedBuffer struct{ lock sync.Mutex buffer bytes.Buffer

}

O pacote também tem uma sincronia RWMutex: um bloqueio que permite que muitos segmentos de leitores usando RLOCK ( ), mas apenas um thread de gravador. Se Lock ( ) é usado, a seção está bloqueado para escrever como com o Mutex normal. Ele também contém uma função útil once.Do (call), onde uma vez é um variabole do tipo uma vez, o que garante que a chamada de função só será invocado uma vez, independentemente do número de uma vez.

Não (chamada) 's existem.Para situações relativamente simples usando o bloqueio através do pacote de sincronização para que

apenas um thread por vez pode acessar a variável ou o mapa Irá resolver este problema. Se isso retarda feito o programa muito ou provoca outros problemas, a solução deve ser repensado com goroutines e canais em mente: esta é a tecnologia proposta pelo Go para escrever aplicações simultâneas.

Page 292: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

cálculos precisos e o pacote grande.

Sabemos que os cálculos realizados por meio de programação, por vezes, não são precisos. Se você usar o tipo float64 Go em ponto flutuante números cálculo, os resultados são precisos cerca de 15 dígitos decimais, o suficiente para a maioria das tarefas. Ao calcular com números muito grandes de toda a gama dos tipos int64 ou UInt64 também pode ser muito pequeno. Nesse caso float32 ou float64 pode ser usado se a precisão não é uma preocupação, mas se for, não podemos usar números de ponto flutuante, porque eles só são representados por aproximação na memória.

Para a realização de cálculos precisos perfeitamente com valores inteiros Go fornece o pacote grande, contida no pacote de matemática: big.Int para inteiros e big.Rat para números racionais (estes são números que podem ser representados por uma fração como 2/5 ou 3.1416, mas não como números Goracionais e ou π). Estes tipos podem conter um número arbitrário de dígitos, limitada apenas pela memória disponível da máquina. A desvantagem é o maior uso da memória e da sobrecarga de processamento: são muito mais lento do que com o processo embutido inteiros.

Um grande número inteiro é construído com a função big.NewInt (n), onde n é um int64, um grande número racional com big.NewRat (n, d) em que ambos n (o numerador) e d (o denominador) são do tipo int64. Porque Go não suporta sobrecarga de operador todos os métodos das grandes tipos têm nomes, como Add ( ) e Mul ( ). São métodos agindo sobre o inteiro ou racional como receptor, e na maioria dos casos, eles modificar o seu receptor e também retornar o receptor como resultado, de modo que as operações podem ser acorrentado e memória guardada, porque nenhum big.Int temporária variáveis têm que ser criada para conter resultados intermediários.

package mainimport ( “fmt” “math” “math/big”)func main( ) {/ / Aqui estão alguns cálculos com bigInts: im := big.NewInt(math.MaxInt64) in := im io := big.NewInt(1956) ip := big.NewInt(1) ip.Mul(im, in).Add(ip, im).Div(ip, io) fmt.Printf(“Big Int: %v\n”, ip)/ / Aqui estão alguns cálculos com bigInts: e are some calculations with bigInts: rm := big.NewRat(math.MaxInt64, 1956) rn := big.NewRat(-1956, math.MaxInt64) ro := big.NewRat(19, 56) rp := big.NewRat(1111, 2222) rq := big.NewRat(1, 1) rq.Mul(rm, rn).Add(rq, ro).Mul(rq, rp) fmt.Printf(“Big Rat: %v\n”, rq)}

/ * Saída:Big Int: 43492122561469640008497075573153004Rat Big: -37 / 112* /

pacotes e visibilidade sob encomenda

Os pacotes são o principal meio de de organizar e compilar o código. Agora vamos ver exemplos concretos do uso de pacotes que você

Page 293: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

escreve sozinho. Nas próximas seções, vamos rever alguns pacotes da biblioteca padrão. Por pacotes personalizados queremos dizer pacotes de auto-escrito ou de outra forma externa para a biblioteca padrão.

Ao escrever seus próprios pacotes, utilize, de uma única palavra curta, nomes em minúsculas, sem _ para o nome do arquivo. Aqui está um exemplo simples de como os pacotes podem encontrar uns aos outros e como a regra Visibilidade funciona:

Nosso diretório atual contém o package_test.go programa. Ele usa código de um programa que pack1.go está contido no pack1 pacote personalizado. Este programa (juntamente com a sua compilado e ligado arquivados forma pack1.a) reside em um pack1 subdiretório do nosso diretório atual, por isso o vinculador liga o código objeto do pacote (s), juntamente com o código-objeto do programa principal.

package pack1var Pack1Int int = 42var pack1Float = 3.14func ReturnStr( ) string { return “Hello main!”}

Exporta uma Pack1Int variável int e um ReturnStr função que retorna um string. Este programa não faz nada quando ele é executado, uma vez que não contém um main ( ) função.

No principal programa package_test.go o pacote é importado através da declaração

import “./pack1/pack1”

O formato geral da importação é:

import “path or url to the package” like import “github.com/org1/pack1”

Se é um caminho é relativo ao diretório do pacote atual.

package mainimport (

“fmt”“./pack1/pack1”

)func main( ) {

var test1 string test1 = pack1.ReturnStr( ) fmt.Printf(“ReturnStr from package1: %s\n”, test1) fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int) / / fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)

}

Saída:

ReturnStr from package1: Hello main!Integer from package1: 42

No caso de o pacote pack1 seria na mesma planta como o nosso programa atual, pode ser importado com: import "./pack1", mas isso não é considerado uma boa prática.

A linha fmt.Printf ("Flutuar de package1:% f \ n", pack1.pack1Float), tentando acessar uma variável ou função não exportadas, nem sequer compilar. Ele dá o erro:

não pode referir-se o nome não exportadas pack1.pack1FloatOs pacotes que são utilizados pelo principal programa deve ser construído antes da compilação do

programa principal. Cada exportado pack1-Item que é usado no programa principal deve ser qualificado pelo nome do pacote: pack1.Item.

Então, por convenção, há uma estreita relação entre os subdiretórios e pacotes: cada pacote (todos os go-arquivos pertencentes a ele) reside em seu próprio subdiretório, que tem o mesmo nome do pacote.

Para maior clareza diferentes pacotes de residir em diretórios diferentes.Importe com: import . “./pack1”"Ao utilizar. Como um alias, pode-se usar os itens do pacote, sem qualificação, com os seus nomes de

Page 294: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

pacotes, como por exemplo em: teste1 = ReturnStr ( ).Importa pack1 no namespace atual, geralmente considerado bom apenas para fins de teste.Importe com _: import _ “./pack1/pack1”O pack1 pacote é importado apenas para seus efeitos colaterais, isto é: as suas funções de

inicialização são executados e variáveis globais inicializadas.Importação de pacotes externos instalados:Se você precisa de um ou mais pacotes externos em seu aplicativo, você primeiro terá que instalá-los

localmente em sua máquina com o comando vai instalar.Suponha que você queira usar um pacote (fictício) onde Code site poderia ser GoogleCode, github,

bitbucket, barra de ativação ou outros;.. ext = a extensão, como com ou org, e goex é o nome do pacote (muitas vezes estes começam com movimento, de modo algum, uma convenção necessário)

Você instala este com o comando: go install codesite.ext/author/goExample/goexIsso instala o código no mapa codesite.ext / autor / goExample / goex menos de US $ GOROOT / src /Uma vez instalado, para importá-lo em seu código, use:import goex “codesite.ext/author/goExample/goex”Assim, o caminho de importação será a URL acessível via web para raiz do seu projeto seguido do

subdiretório.A execução do programa começa com a importação dos pacotes, inicializar o package main e, em

seguida, invocando a função main ( ).Um pacote com nenhuma importação é inicializado através da atribuição de valores iniciais para todas

as suas variáveis de nível de pacote e, em seguida, chamar qualquer de nível de pacote função init ( ) definido na sua fonte. Um pacote pode conter inicialização múltipla (funções), mesmo dentro de um único arquivo de origem; eles executam de forma não especificada. É a melhor prática se a determinação dos valores de um pacote só dependem de outros valores ou funções encontradas no mesmo pacote.

Init ( ) funções não podem ser chamados.Pacotes importadas são inicializados antes da inicialização da própria embalagem (com a exceção do

principal), mas a inicialização de um pacote ocorre apenas uma vez na execução de um programa.

Construção e instalação de um pacote:

include $(GOROOT)/src/Make.incTARG=pack1GOFILES=\

pack1.go\ pack1b.go\

include $(GOROOT)/src/Make.pkg

E torná-lo executável com chmod 777. / Makefile.

A incluir declarações puxar funcionalidade que detecta automaticamente a arquitetura da máquina e usa o compilador e vinculador correto.

Em seguida, execute make na linha de comando ou o gomake toll: ambos make a map _obj contendo o static library pack1.a.

O comando go install também copia pack1.a ao funcionário pacotes locais mapa $ GOROOT / pkg, num submap com o nome do sistema operacional (como o Linux). Quando este é feito o pacote pode ser importado em um programa simplesmente pelo seu nome, como o de importação "pack1" em vez de importar "caminho para PACK1".

9,6 Usando GoDoc para seus pacotes personalizados.

A ferramenta GoDoc funciona também muito bom para mostrar os comentários em seu próprio pacote: os comentários devem começar com / / e precedem as declarações (de pacotes, tipos, funções ...) sem linha em branco no meio. GoDoc produzirá Irá produzir uma série de páginas HTML, uma para cada arquivo de Go.

Por exemplo:- No doc_example mapa temos a go-arquivos tipo e sortmain com alguns comentários no arquivo tipo

(os arquivos não precisa ser compilado);- Navegar na linha de comando para este mapa e começar o comando:GoDoc-http =: 6060-path = "."

Page 295: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

. (É o mapa atual, o sinalizador-caminho pode ser da forma / path/to/my/package1 onde o package1 mapa contém as fontes, ou aceitar uma lista de pontos (: caminhos)-separados;

caminhos não enraizadas são relativos ao diretório de trabalho atual.- Abra um navegador no endereço http:/ /localhost:6060Você, então, ver a página GoDoc local com a esquerda a partir dos pacotes apontam um link para o

seu mapa doc_example:doc_example | Packages | Commands | SpecificationAbaixo, está uma visão geral ordenada de links para a fonte e todos os objetos dentro dela (por isso é

bom para navegar e olhando para cima no código fonte), juntamente com a documentação / comentário:

Package sort

func Float64sAreSorted type IntArrayfunc IntsAreSortedfunc IsSortedfunc Sort func (IntArray) Lenfunc SortFloat64s func (IntArray) Lessfunc SortInts func (IntArray) Swapfunc SortStrings type Interfacefunc StringsAreSorted type StringArraytype Float64Array func (StringArray) Lenfunc (Float64Array) Len func (StringArray) Lessfunc (Float64Array) Less func (StringArray) Swapfunc (Float64Array) Swap Other packages

import “doc_example”

documentação Pacote com GoDocSe você trabalha em equipe e da árvore de origem é armazenado em um disco de rede, você pode

iniciar o processo de GoDoc nele para dar um apoio contínuo documento a todos os membros da equipe. Com a-sync e-sync_minutes = n, você pode até mesmo torná-lo automaticamente atualizar a documentação a cada n minutos!

Usando vão instalar para a instalação de pacotes personalizados.

Go instala a ferramenta de instalação de pacotes automático do Go: ele instala pacotes, baixá-los a partir de repositórios remotos através da internet, se necessário e instalá-los no computador local: checkout, compilar e instalar de uma só vez.

Instala-se cada um dos pacotes de dados na linha de comando, ele instala os pré-requisitos de um pacote antes de tentar instalar o pacote em si e lida com as dependências automaticamente. As dependências dos pacotes que residem na submapas também são instalados, mas a documentação ou exemplos não são: eles são navegável no site.

A lista de todos os pacotes instalados podem ser encontrados em $ GOROOT / goinstall.logEle usa o GOPATH variável.

Pacotes remotos:

Suponha que deseja instalar o pacote marisma interessante (este contém uma série de rotinas úteis, consultehttp:/ /code.google.com/p/tideland-cgl/).

Porque precisamos de criar direitos diretório em algum submapas do Go-instalação, é preciso emitir o comando como root ou su.

Certifique-se de que as variáveis Go-ambiente estão devidamente configuradas no .bashrc file para root. Instale com o comando: go install tideland-cgl.googlecode.com/hg

Isso coloca o hg.a arquivo executável no mapa $ GOROOT/pkg/linux_amd64/tideland-cgl.googlecode.com, e coloca os Go-fonte arquivos em $ GOROOT / src / marisma-cgl.googlecode.com /hg, e também hg.a num _obj submap.A partir de então a funcionalidade do pacote pode ser usado no código Go, usando por exemplo, como

nome do pacote cgl, através da importação:import cgl “tideland-cgl.googlecode.com/hg” De Go 1 em diante vai instalar vai esperar caminhos de importação de código do Google para ser da

Page 296: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

forma:" code.google.com / p / marisma-CGL ".Após a atualização para uma nova versão Go todos os binários do pacote de pacotes instalados

localmente são excluídos.Ao invocar Go instalar-a a ferramenta reinstala todos os pacotes instalados anteriormente, a leitura da

lista de $ GOROOT / goinstall.log. Se você deseja atualizar, recompilar e reinstalar todos os pacotes goinstalled, use go install —a –u –clean ou go install –a –u –nuke

Porque comunicados Go eram frequentes, deve-se tomar cuidado para verificar o lançamento contra o qual o pacote é construir, após Go 1 é o suficiente para saber que era construir contra ela.

go install também pode ser usado para compilar / link e instalar localmente seus próprios pacotes.Mais informações podem ser encontradas em http:/ /golang.org.

Mapa estrutura para pacotes personalizados

A seguinte estrutura dá-lhe um bom começo (onde uc significa um nome de pacote geral; os nomes em negrito são os mapas, em itálico é o executável): / home / user / goprograms

ucmain.go (main program for using package uc)Makefile (2—makefile for ucmain)ucmainsrc/uc (contains go code for package uc)

uc.go uc_test.go Makefile (1—makefile for package) uc.a _obj

uc.a _test

uc.abin (contains the estreitol executable files)

ucmainpkg/linux_amd64

uc.a (object file of package)

Coloque seus projetos em algum lugar em um mapa goprograms (você pode criar uma variável de ambiente GOPATH, coloque o GOPATH linha de export GOPATH=/home/user/goprograms no perfil e bashrc..), E seus pacotes como submapas de src. A funcionalidade é implementada em uc.go, pertencente à uc pacote:

package ucimport “strings”func UpperCase(str string) string { return strings.ToUpper(str)}

O pacote deve ser sempre acompanhada por um ou mais testfiles, aqui fizemos uc_test.go, ao longo das linhas explicado e demonstrado no § 9.8

package ucimport “testing”type ucTest struct { in, out string}var ucTests = [ ]ucTest {

ucTest{“abc”, “ABC”}, ucTest{“cvo-az”, “CVO-AZ”}, ucTest{“Antwerp”, “ANTWERP”},

}

Page 297: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func TestUC(t *testing.T) { for _, ut := range ucTests {

uc := UpperCase(ut.in) if uc != ut.out {

t.Errorf(“UpperCase(%s) = %s, must be %s.”, ut.in, uc, ut.out)

} }}

Construir e instalar o pacote localmente com o comando: go install src/uc isso copia a uc.a para pkg/linux_amd64.

Alternativamente, utilizando fazer: colocar no mapa src / uc um Makefile (1) para o pacote com o seguinte conteúdo:

include $(GOROOT)/src/Make.incTARG=ucGOFILES=\ uc.go\include $(GOROOT)/src/Make.pkg

Na linha de comando neste mapa de invocação: gomakeIsso faz com mapa _obj e coloca o arquivo de pacotes compilados uc.aO pacote pode, em seguida, ser testado com: Go testIsso faz com que o _test mapa com uc.a nele, a saída dá: PASS, de modo que os testes são OK.Observação:

É possível que sua conta corrente não tem direitos suficientes para executar e instalar Go (permissão negada erro). Nesse caso, mude para o usuário root su. Certifique-se de que as variáveis de ambiente, o caminho para o binários também são definidos para su, como para a sua conta normal.

Então nós fazemos o nosso programa de partida principal como ucmain.go:

package mainimport ( “fmt” “./uc/uc”)func main( ) { str1 := “USING package uc!” fmt.Println(uc.UpperCase(str1))}

Em seguida, basta emitir o comando go install neste mapa.Como alternativa, copie uc.a no mapa uc e colocar um Makefile (2) ao lado dela com o texto:

TARG=ucmainGOFILES=\ucmain.go\include $(GOROOT)/src/Make.cmd

Emissão gomake compila ucmain.go para ucmain.Correndo./ucmain gives: Usando o pacote uc!

Page 298: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

localmente instalar o pacote

Pacotes locais no mapa do usuário:Usando o determinado mapa-estrutura, os seguintes comandos podem ser usados para instalar os

pacotes locais da fonte:

go install /home/user/goprograms/src/uc # build and install uccd /home/user/goprograms/ucgo install ./uc # build and install uc (= does same as previous command)cd ..go install . # build and install ucmain

Instalação menor de US $ GOROOT:

Se queremos que o pacote a ser usado a partir de qualquer programa Go no sistema, ele deve ser instalado abaixo de US $ GOROOT.

Para fazer isso, deestreito GOPATH = $ GOROOT no perfil e bashrc,.. Então vá1) cópia do código fonte a US $ GOROOT/src/pkg/linux_amd64/uc2) copiar o arquivo de pacotes para US $ GOROOT/pkg/linux_amd64/ucEle pode então ser importado em qualquer Go-source como: import uc

OS código dependente

É muito raro que o seu programa deve codificar de forma diferente de acordo com o sistema operacional em que ele está indo para executar: na grande maioria dos casos, as questões mais portabilidade da linguagem e do punho biblioteca padrão.Você poderia ter uma boa razão para escrever código específico da plataforma, como o suporte de linguagem de montagem.

Nesse caso, é razoável seguir esta convenção:

prog1.goprog1_linux.goprog1_darwin.goprog1_windows.go

define a interface de código comum acima diferentes sistemas operacionais, e colocar oCódigo específico do sistema operacional em seu próprio Go-arquivo chamado prog1_os.go

Para a ferramenta de Go então você pode especificar: prog1_$GOOS.go or prog1_$GOARCH.goou no Makefile plataforma: prog1_$(GOOS).go\ or prog1_$(GOARCH).go\

Usando uma biblioteca externa em um programa Go.

Ao iniciar um novo projeto ou a adição de novas funcionalidades a um projeto existente você pode economizar tempo de desenvolvimento através da incorporação de um Go-biblioteca já existente em sua aplicação. Para fazer isso você tem que entender a API (Application Programming Interface) da biblioteca, ou seja: quais métodos você pode chamar esta biblioteca e como chamá-los. Poderia realmente ser possível que você não tem a fonte dessa biblioteca, mas os fabricantes, então, certamente, têm documentado a API e detalhada como usá-lo.

Como exemplo, vamos escrever um pequeno programa usando o urlshortener de APIs do Google: você pode experimentá-lo em http:/ /goo.gl/. Digite uma URL como http:/ /www.destandaard.be e você verá

Page 299: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

uma URL mais curta retornou como http:/ /goo.gl/O9SUO, que é muito mais fácil de incorporar, por exemplo, em um serviço como o twitter.Documentação para o serviço urlshortener Google podem ser encontradas em http:/ /code.google.com.br / apis / urlshortener /.

Google torna esta tecnologia disponível para outros desenvolvedores como uma API que podemos chamar de nossas próprias aplicações (grátis até um determinado limite). Eles também têm gerado um cliente de biblioteca Go para torná-lo ainda mais fácil.

Observação:Google tornou a vida mais fácil para desenvolvedores Go para utilizar os seus serviços, fornecendo-

lhes os clientes Google API Go. Os programas de Go-cliente onde gerados automaticamente a partir do JSON-descrição das bibliotecas do Google. Você pode ler mais sobre ele em http:/ /code.google.

com / p / google-api-go-cliente /.Baixar e instalar a biblioteca cliente Go:Mas, primeiro verifique se a variável GOPATH está definido em seu ambiente, porque o código fonte

externa será baixado para o diretório $ GOPATH / src e os pacotes também será instalado neste diretório $ GOPATH / pkg / "MACHINE_ARCH" /.

Em seguida, vamos instalar o API, invocando o seguinte comando no console:go install google-api-go-client.googlecode.com/hg/urlshortener/v1go install Irá baixar o código fonte, compilar e instalar o pacote.(Em Linux Ubuntu com 6g r60 9481 instalação funciona bem, o pacote instalado é abaixo pkg /

linux_amd64.)Um programa de internet para usar o serviço urlshortener:Podemos agora usar o pacote instalado em nossos programas por importá-lo e dar-lhe um apelido

(para digitar menos): urlshortener importação "google-api-go-client.googlecode.com/hg/urlshortener/v1"Vamos agora escrever um aplicativo web, que mostra um formulário web onde você pode dar em um

longo url e pedir um curto url, eo inverso. Para isso, use o pacote de templates e escrevemos três funções do identificador: o manipulador de raiz mostra a forma por meio da execução do modelo de formulário, o curta-manipulador (para URLs da forma / curtas) acrescentar a isto, tomando um longo url e retorna a curto url, ea longa handler (URLs da forma / longo) faz o inverso.

Estruturas e Métodos

Go suporta tipos definidos pelo usuário ou personalizados na forma de tipos de alias ou estruturas. A struct tenta representar uma entidade do mundo real com suas propriedades.Estruturas são tipos compostos, para usar quando você quer definir um tipo que consistem em uma série de propriedades, cada um com seu próprio tipo e valor, agrupando pedaços de dados em conjunto. Em seguida, pode-se acessar os dados como se fosse parte de uma única entidade.

Eles também são tipos de valor e assim são construídos com a nova função.As peças componentes de dados que constituem o tipo struct são chamados campos. Um campo tem

um tipo e um nome, nomes de campos dentro de uma estrutura deve ser exclusivo.O conceito foi chamado ADT (Abstract Data Type) em textos mais antirás sobre engenharia de

software, foi chamado um registro em linguagens mais antigas como Cobol, e também existe sob o mesmo nome de struct no C-família de línguas, nas linguagens OO como uma classe leve, sem métodos. No entanto, porque Go não tem o conceito de uma classe, o tipo de estrutura tem um lugar muito mais importante em Go.

O formato geral da definição de uma struct (estrutura) é a seguinte:

type identifier struct { field1 type1 field2 type2 ...

}Também type T struct {a, b} int é a sintaxe legal, e mais adequado para estruturas simples.Os campos nesta struct têm nomes, como campo1, campo2, etc Se o campo não é usado no código,

ele pode ser chamado _.Esses campos podem ser de qualquer tipo, mesmo instrui a si mesmos, funções ou interfaces .Porque

um struct é um valor, podemos declarar uma variável do tipo struct, e dar os seus valores de campos, tais como:

var s T

Page 300: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

s.a = 5s.b = 8Uma array pode ser visto como uma espécie de estrutura, mas com indexada ao invés de campos

nomeados.Usando new:Memória para uma nova variável struct é alocado com a nova função, que retorna um ponteiro para o

armazenamento alocado: var t *T = new (T), que pode ser colocado em diferentes linhas, se necessário (por exemplo, quando a declaração tem que ser escopo do pacote, mas a destinação não é necessário no início):

var t *Tt = new(T)

O idioma para escrever este mais curto é: t := new(T), a variável t é um ponteiro para T: neste momento os campos contêm os valores de zero de acordo com seus tipos.

No entanto declarando var t T também aloca e zero inicializa memória para t, mas agora t é do tipo T.Em ambos os casos t é comumente chamado de uma instância ou objeto do tipo T.

package mainimport “fmt”type struct1 struct {

i1 int f1 float32 str string

}func main( ) {

ms := new(struct1) ms.i1 = 10 ms.f1 = 15.5 ms.str = “Chris” fmt.Printf(“The float is: %f\n”, ms.f1) fmt.Printf(“The string is: %s\n”, ms.str) fmt.Println(ms)

}

Saisa: The int is: 10

The float is: 15.500000 The string is: Chris &{10 15.5 Chris}

O padrão (de modo% v) cópia impressa de um struct com fmt.Println ( ) mostra bem o seu conteúdo.Os campos podem ser dado um valor diferente, usando a notação de ponto, como é costume em OO-

idiomas:structname.fieldnameOs valores dos campos de struct pode ser recuperada com a mesma notação: structname.fieldname

Isso é chamado de um seletor no Go. Para acessar os campos de um struct, se a variável é do tipo struct ou um ponteiro para o tipo struct, usamos o mesmo seletor-notação:

type myStruct struct { i int }var v myStruct / / v has struct typevar p *myStruct / / p is a pointer to a structv.ip.i

Uma notação ainda mais curta ea forma idiomática para inicializar uma instância struct (uma estrutura-literal) é o seguinte:

ms := &struct1{10, 15.5, “Chris”}/ / Isto significa que ms é do tipo * Struct1var mt struct1

Page 301: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

mt = struct1{10, 15.5, “Chris”}

A sintaxe e Struct1 literal composto {a, b, c} é um atalho; debaixo das cobertas que ainda chama new ( ); os valores devem ser dadas em campo ordem. No exemplo a seguir, vemos que você também pode inicializar valores precedendo-os com os nomes de campos. Tão novo (Tipo) e & Type { } são equivalentes expressões.

Um exemplo típico de um struct é um tempo de intervalo (com início e fim do tempo expresso aqui em segundos):

type Interval struct { start int

end int}

E aqui estão algumas inicializações:

inter := Interval{0,3} (A)inter2 := Interval{end:5, start:1} (B)inter3 := Interval{end:5} (C)

No caso de (A) os valores indicados no literal deve ser exatamente na mesma ordem em que os campos são definidos na estruct, o e não é obrigatória. Processo (B) mostra uma outra possibilidade que os nomes dos campos com um: preceder o valor, caso em que a sua sequência não deve ser o mesmo, e os campos podem também ser omitido, como no caso de (C).

A nomeação do tipo struct e seus campos adere à regra Visibilidade, é possível que um tipo struct exportado tem uma mistura de campos: alguns exportados, outros não.

A figura a seguir esclarece o layout de memória de um valor de estrutura e um ponteiro para um struct para o seguinte tipo de estrutura: tipo Point struct {x, y int}

Inicializado com o new:Iniciado como um literal struct:Um tipo Struct1 deve ser exclusivo na pack1 pacote no qual ela está definida, seu nome de tipo

completo é: pack1.struct1O exemplo a seguir Listagem de 10,2 person.go mostra uma pessoa struct, um método upPerson que

tem um parâmetro do tipo * Pessoa (de modo que o próprio objeto pode ser alterado!) E 3 formas diferentes de chamar esse método:

package mainimport (

“fmt” “strings”

)type Person struct {

firstName lastName

stringstring}func upPerson (p *Person) {

p.firstName = strings.ToUpper(p.firstName) p.lastName = strings.ToUpper(p.lastName)

}func main( ) {

/ / 1 - struct como um tipo de valor: var pers1 Person pers1.firstName = “Chris” pers1.lastName = “Woodward” upPerson(&pers1) fmt.Printf(“The name of the person is %s %s\n”, pers1.firstName, pers1. lastName)

Page 302: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

/ / 2-estrutura como um ponteiro: pers2 := new(Person) pers2.firstName = “Chris” pers2.lastName = “Woodward” (*pers2).lastName = “Woodward” / / Esta é também valido upPerson(pers2) fmt.Printf(“The name of the person is %s %s\n”, pers2.firstName, pers2. lastName)

/ / 3-estrutura como um literal: pers3 := &Person{“Chris”,“Woodward”} upPerson(pers3) fmt.Printf(“The name of the person is %s %s\n”, pers3.firstName, pers3. lastName)

}

/ * Saída:The name of the person is CHRIS WOODWARDThe name of the person is CHRIS WOODWARDThe name of the person is CHRIS WOODWARD* /

caso 2, vemos que a definição de um valor através de um ponteiro como em pers2.lastName = "Woodward" funciona, não há nenhum operador -> necessário como em C + +: Go faz a conversão automaticamente.

Note que também pode definir o valor por dereferencing o ponteiro:(*pers2).lastName = “Woodward”As estruturas e layout de memória:Estructs em Go e os dados neles contidos, mesmo quando um struct contém outras estruturas, formam

um bloco contínuo de memória: isso dá uma enorme vantagem de desempenho. Isso é diferente em Java, com seus tipos de referência, onde um objeto e seus objetos contidos podem estar em diferentes partes da memória, em Go este é também o caso com pointers.This é claramente ilustrado no exemplo a seguir:

type Rect1 struct { Min, Max Point }type Rect2 struct { Min, Max *Point }

Estructs recursivas:

Um tipo de estruct pode ser definida em termos de si. Isso é particularmente útil quando a variável struct é um elemento de uma lista ligada ou uma árvore binária, comumente chamado de nó. Nesse caso, o nó contém links (os endereços) para os nós vizinhos; su para uma lista e le, ri para uma árvore são ponteiros para outra variável Node. onde o campo de dados contém as informações úteis (por exemplo, um float64) e su aponta para o nó sucessor; em Go-código:

type Node struct {data float64 su *Node

}

O primeiro elemento da lista é chamada de cabeça, ele aponta para o segundo elemento, o último elemento é chamado de cauda, ele não aponta para qualquer sucessor, então seu campo su tem valor nulo. É claro que em uma lista real, teríamos muitos-nós de dados, a lista pode aumentar ou diminuir de forma dinâmica.

Da mesma forma, você pode definir uma lista duplamente ligada com um campo pr nó antecessor e sucessor de um campo su.

Tipo de nó struct {type Node struct {

pr *Node data float64

Page 303: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

su *Node}

Aqui, cada nó pode, no máximo, ter links para outros dois nós: o esquerdo (OE) e à direita (ri); ambos podem propagar este projecto. O elemento de topo da árvore é chamado de raiz, a camada inferior de nós que não têm mais nós abaixo deles são chamadas as folhas, um nó licença tem valores nulos para os le-ri e ponteiros. Esse nó é uma árvore em si mesma, para que pudéssemos escrever: em Go-código:

type Tree struct {le *Treedata float64 ri *Tree

}

Conversão de estruturas:

Como já vimos conversão em Go segue regras rígidas. Quando temos um tipo struct e definir um tipo de alias para ele, ambos os tipos têm o mesmo tipo subjacente e podem ser convertidos um no outro, mas também observar os casos de compilação de erros que denotam atribuições impossíveis ou conversões:

Listagem 10.3-struct_conversions.go:package mainimport “fmt”type number struct { f float32}type nr number / / alias typefunc main( ) { a := number{5.0}

b := nr{5.0} / / var i float32 = b

/ / compile-error: cannot use b (type nr) as type / / var i float32 = b / / compile-error: cannot use b (type nr) as type float32 in assignment / / var i = float32(b) / / compile-error: cannot convert b (type nr) to type float32 / / var c number = b / / compile-error: cannot use b (type nr) as type number in assignment / / needs a conversion: var c = number(b) fmt.Println(a, b, c)}/ / Output: {5} {5} {5}

Criando uma variável struct com um método de Factory

O Go não suporta construtores como Java e C++, mas as funções de factory do como dos construtores são fáceis de implementar. Muitas vezes, uma fábrica é definida para o tipo de conveniência, por convenção um nome que começa com o novo ou nova. Suponha que definir um tipo struct arquivo:

intype File struct {fd int / / Arquivo número do descritorname string / / nome do arquivo

Page 304: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}

Em seguida, a fábrica, que retorna um ponteiro para o tipo de estrutura, seria:

func NewFile(fd int, name string) *File { if fd < 0 { return nil

} return &File{fd, name}

}

Muitas vezes, um construtor Go pode ser escrito de forma sucinta usando inicializadores dentro da função de fábrica.

Um exemplo de chamá-lo:

f := NewFile(10, “./test.txt”)

Se arquivo é definido como um tipo de estrutura, a expressões new(File) e &File{ } são equivalentes.Compare isso com as inicializações desajeitados na maioria das linguagens OO: ArquivoEm geral podemos dizer que a fábrica instancia um objeto do tipo definido, assim como nas linguagens

baseadas em classes.Se você tem um tipo struct T e você quer rapidamente ver quantos bytes ocupa uma instância na

memória, use: tamanho: = unsafe.Sizeof (T { })

Como forçar o uso do método de fábrica:

Aplicando a regra de Visibilidade, podemos forçar o uso do método de fábrica e proibGo o uso novo, efetivamente tornando o nosso tipo particular, como é chamado em idiomas orienbtadas a objetos.

package matrixtype matrix struct { ...}function NewMatrix(params) *matrix {

m := new(matrix)/ / M é inicializado return m}

Por causa da m de array, precisamos usar o método de fábrica em outro pacote:

package mainimport “matrix”...wrong := new(matrix.matrix) / / não Irá compilar (array é privado)right := matrix.NewMatrix(...) / / a única maneira de instanciar uma array

new ( ) e maker ( ) revisitado para mapas e estruturas:

Até agora temos visto 2 dos 3 tipos para os quais fazem ( ) pode ser usado:

slices / maps / channels Para ilustrar a diferença de comportamento para os mapas e os possíveis erros, experiência com o

seguinte programa:

package maintype Foo map[string]string

Page 305: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

type Bar struct { thingOne string thingTwo int

}func main( ) {

/ / OK: y := new(Bar) (*y).thingOne = “hello” (*y).thingTwo = 1

/ / Não OK: z := make(Bar) / / erro de compilação.

z := make(Bar) / / compile error: cannot make type Bar z.thingOne = “hello” z.thingTwo = 1 / / OK: x := make(Foo) x[“x”] = “goodbye” x[“y”] = “world” / / não OK: u := new(Foo) (*u)[“x”] = “goodbye” / / !! panic !!: erro de execução: Atribuição de entrada in nil map (*u)[“y”] = “world”

}

Para tentar fazer ( ) uma variável struct não é tão ruim, o compilador começa o erro, mas newing um mapa e tentar preenchê-lo com dados dá um erro de tempo de execução! new(Foo) é um ponteiro para um nulo, ainda não atribuído, mapa: que deve ter muito cuidado com isso!

pacote personalizado usando estruturas

package structPacktype ExpStruct struct {

Mi1 int Mf1 float

}

Exemplo:

package mainimport (

“fmt” “./struct_pack/structPack”)func main( ) {

struct1 := new(structPack.ExpStruct) struct1.Mi1 = 10 struct1.Mf1 = 16. fmt.Printf(“Mi1 = %d\n”, struct1.Mi1) fmt.Printf(“Mf1 = %f\n”, struct1.Mf1)

}

Saída:Mi1 = 10MF1 = 16.000000

Estruturas com etiquetas

Page 306: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Um campo em um struct pode, além de um nome e um tipo, também, opcionalmente, um tag: este é um fio ligado ao campo, que poderia ser de documentação ou algum outro rótulo importante. O conteúdo-tag não pode ser usado na programação normal, apenas o pacote refletir pode acessá-lo. 

package mainimport (

“fmt” “reflect”

)type TagType struct { / / tags field1 bool “An important answer” field2 string “The name of the thing”

field3 int “How much there are”}

func main( ) { tt := TagType{true, “Minha Casa”, 1} for i:= 0; i < 3; i++ {

refTag(tt, i) }}

func refTag(tt TagType, ix int) { ttType := reflect.TypeOf(tt) ixField := ttType.Field(ix)

fmt.Printf ("% v \ n", ixField.Tag)}

/ * Saída:

An important answerThe name of the thingHow much there are * /

campos anônimos e estruturas incorporados

Às vezes pode ser útil ter estruturas que contêm um ou mais campos anônimos (ou embutidos), ou seja campos com nenhum nome explícito. Apenas o tipo de tal campo é obrigatório e, em seguida, o tipo é também o seu nome. Tal campo anônimo também pode ser em si uma estrutura: estruturas podem conter estruturas incorporadas.

Isso se compara vagamente ao conceito de herança nos OO-línguas e, como veremos, pode ser usado para simular um comportamento muito parecido com herança. Isto é obtido pela incorporação ou composição, por isso, podemos dizer que na composição de Go é favorecido sobre herança.

package mainimport “fmt”type innerS struct {

in1 int in2 int

}type outerS struct {

b int c float32 int / / anonymous field innerS / / anonymous field

}

Page 307: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func main( ) { outer := new(outerS) outer.b = 6 outer.c = 7.5 outer.int = 60 outer.in1 = 5 outer.in2 = 10 fmt.Printf(“outer.b is: %d\n”, outer.b) fmt.Printf(“outer.c is: %f\n”, outer.c) fmt.Printf(“outer.int is: %d\n”, outer.int) fmt.Printf(“outer.in1 is: %d\n”, outer.in1) fmt.Printf(“outer.in2 is: %d\n”, outer.in2)

/ / Com um struct-literal: outer2 := outerS{6, 7.5, 60, innerS{5, 10}} fmt.Println(“outer2 is: “, outer2)

}

Saída: outer.b é: 6outer.c é: 7.500000outer.int é: 60outer.in1 é: 5outer.in2 é: 10outer2 é: {6 7,5 60 5 {10}}Para armazenar dados em um campo anônimo ou ter acesso aos dados que usamos o nome do tipo

de dados: outer.int,a conseqüência é que só podemos ter um campo anônimo de cada tipo de dados em uma struct.

estruturas Embarcadas

Como uma estrutura é também um tipo de dados, ele pode ser utilizado como um campo anónimo, ver o exemplo acima. A estrutura externa podem acessar diretamente os campos da struct interna com outer.in1, este é mesmo o caso quando o struct incorporado vem de outro pacote. A estrutura interna é simplesmente inserido ou "incorporado" na exterior. Este mecanismo simples 'herança' fornece uma maneira de obter algum ou todos os seus implementação de outro tipo ou tipos.

package mainimport “fmt”type A struct { ax, ay int}type B struct {

A bx, by float32

}func main( ) {

b := B{A{1, 2}, 3.0, 4.0} fmt.Println(b.ax, b.ay, b.bx, b.by) fmt.Println(b.A)

}

Saída: 1234 {1 2}

Métodos

Estruturas parecer uma forma simples de aulas, portanto, um programador OO pode perguntar: onde estão os métodos da classe? Novamente Go tem um conceito com o mesmo nome e aproximadamente o mesmo significado: um método Go é uma função que atua sobre variável de um determinado tipo, o

Page 308: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

chamado receptor. Assim, um método é um tipo especial de função.O tipo de receptor pode ser (quase) qualquer coisa, não é apenas um tipo struct: qualquer tipo pode ter

métodos, até mesmo um tipo de função ou de alias tipos para int, bool, strins ou array. O receptor também não pode ser um tipo de interface, uma vez que uma interface é a definição abstrata e um método é a implementação, tentando fazê-lo gera o erro do compilador: tipo de receptor inválido ...

Estreitolmente, não pode ser um tipo de ponteiro, mas pode ser um indicador para qualquer um dos tipos permitidos.

A combinação de um (struct) tipo e seus métodos é o equivalente Go de uma classe em OO. Uma diferença importante é que o código para o tipo e os métodos de ligação a ela não são agrupados juntos, eles podem existir em diferentes ficheiros de origem, a única exigência é que eles têm de estar no mesmo pacote.

A coleção de todos os métodos em um determinado tipo T (ou * T) é chamado o conjunto método de T (ou * T).

Métodos são funções, por isso novamente não há nenhuma sobrecarga de método: para um determinado tipo, não existe apenas um método com um determinado nome. Mas, com base no tipo de receptor, não há sobrecarga: um método com o mesmo nome pode existir em duas de mais tipos de receptores diferentes, por exemplo, isso é permitido no mesmo pacote:

func (a *denseMatrix) Add(b Matrix) Matrixfunc (a *sparseMatrix) Add(b Matrix) Matrix

Também um apelido para um determinado tipo não tem os métodos definidos nesse tipo.O formato geral de um método é:

func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }

O receptor é especificado em ( ) antes do nome do método após a palavra-chave função.Se recv é a instância receptor e Method1 o nome do método, então a chamada ou a invocação do

método segue o tradicional objeto.método seletor de notação: recv.Method1( )Nesta expressão se recv é um ponteiro, então ele é automaticamente desreferenciado.Se o método não precisa usar o valor recv, você pode descartá-lo por subsituting a _, como em:func (_ receiver_type) methodName(parameter_list) (return_value_list) { ... }

recv é como o presente ou auto existente em OO-línguas, mas em Go não há nenhuma palavra-chave especificada para ele;

se você gosta você pode usar auto ou este como o nome para a variável do receptor, mas você pode escolher livremente. Aqui está um exemplo simples de métodos em uma struct:

package mainimport “fmt”type TwoInts struct {

a int b int

}func main( ) {

two1 := new(TwoInts) two1.a = 12 two1.b = 10 fmt.Printf(“The sum is: %d\n”, two1.AddThem( )) fmt.Printf(“Add them to the param: %d\n”, two1.AddToParam(20)) two2 := TwoInts{3, 4} fmt.Printf(“The sum is: %d\n”, two2.AddThem( ))

}func (tn *TwoInts) AddThem( ) int {

Saída:

A soma é: 22Adicione-os e param: 42A soma é: 7

Page 309: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport “fmt”type IntVector [ ]intfunc (v IntVector) Sum( ) (s int) {

for _, x := range v {s += x

} return

}func main( ) {

fmt.Println(IntVector{1, 2, 3}.Sum( )) / / Output: 6}

Um método e o tipo em que ele atua devem ser definidos no mesmo pacote, é por isso que você não pode definir métodos de tipo int, float ou similar. Tentar definir um método em um tipo int dá o erro do compilador:Por exemplo, se você deseja definir o método a seguir em time.time:

func (t time.Time) first3Chars( ) string { return time.LocalTime( ).String( )[0:3]}

Você obtém o mesmo erro para um tipo definido em outro, portanto, também não-local, pacote.Mas há uma maneira de contornar: você pode definir um alias para esse tipo (int, float, ...) e, em

seguida, definir um método para esse tipo. Ou incorporar o tipo como um tipo anônimo em uma nova estrutura, como no exemplo a seguir. É claro que este método é, então, só é válido para o tipo de alias.

Listagem 10.12-method_on_time.go:

package mainimport ( “fmt” “time”)type myTime struct { time.Time / /anonymous field}func (t myTime) first3Chars( ) string { return t.Time.String( )[0:3]}func main( ) { m := myTime{time.Now( )} / /calling existing String method on anonymous Time field fmt.Println(“Full time now:”, m.String( )) / /calling myTime.first3Chars fmt.Println(“First 3 chars:”, m.first3Chars( ))}

/ * Saída:Full time now: Mon Oct 24 15:34:54 Romance Daylight Time 2011First 3 chars: Mon* /

Diferença entre uma função e um método

A função tem a variável como um parâmetro: Function1 (recv)Um método é chamado na variável: recv.Method1 ( )

Um método pode alterar os valores (ou o Estado) da variável receptor desde que seja um ponteiro,

Page 310: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

como é o caso de funções (a função também pode alterar o estado de seu parâmetro quando este é passado como um ponteiro: chamada por referência ).

!! Não se esqueça do ( ) depois Method1, ou você recebe o erro de compilação: method is not an expression, must be called !!

O receptor tem de ter um nome explícito, e este nome deve ser utilizado no método.receiver_type é chamado de (receptor) tipo base, este tipo deve ser declarado dentro do mesmo

pacote que todos os seus métodos.Em Go os métodos anexados a um (receptor) tipo não são escritos dentro da estrutura, como é o caso

de classes; o acoplamento é muito mais solta: a associação entre o método eo tipo é estabelecida pelo receptor.

Métodos não são misturados com a definição de dados (as estruturas): eles são ortogonais aos tipos; representação (dados) e comportamento (métodos) são independentes.

Ponteiro ou valor como receptor

recv é mais freqüentemente um ponteiro para a receiver_type por motivos de desempenho, isso é especialmente verdadeiroo quando o tipo de receptor é um struct.

Deestreito o método em um tipo de ponteiro se você precisar do método para modificar os dados dos pontos de recepção para. Caso contrário, é muitas vezes mais limpa para definir o método em um tipo de valor normal.

Isso é ilustrado no exemplo a seguir pointer_value.go: mudança ( ) recebe um ponteiro para B, e muda o seu campo interno; write ( ) só mostra o conteúdo da variável B e recebe o seu valor por cópia. Anúncio no main ( ) que vai faz trabalho de canalização para nós, nós mesmos não temos que descobrir se a chamar os métodos em um ponteiro ou não, Go faz isso para nós. b1 é um valor e b2 é um ponteiro, mas as chamadas métodos funcionam muito bem.

package mainimport ( “fmt”)type B struct { thing int}func (b *B) change( ) { b.thing = 1 }func (b B) write( ) string { return fmt.Sprint(b) }func main( ) {

var b1 B / / b1 é um valor b1.change( ) fmt.Println(b1.write( )) b2 := new(B) / / B2 é um ponteiro b2.change( ) fmt.Println(b2.write( ))

}

/ * Saída:{1}{1}* /

Tente fazer write ( ) alterar o seu valor receptor b: você vai ver que ele compila bem, mas o b original não é alterado!

Vimos que um método não requer um ponteiro como um receptor, como no exemplo a seguir, onde precisamos apenas os valores de Point3 para calcular alguma coisa:

type Point3 struct { x, y, z float }/ / Um método em Point3:func (p Point3) Abs( ) float {

Page 311: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

return math.Sqrt(p.x*p.x + p.y*p.y + p.z*p.z)}

Isto é um pouco caro, porque Point3 será sempre passado para o método por valor e por isso copiado, mas é válido Go. Neste caso, o método também pode ser chamado de um ponteiro para o tipo (há desreferência automática). Suponha p3 é definido como um ponteiro: p3 := &Point3{ 3, 4, 5 } Depois, você pode escrever p3.Abs( ) instead of (*p3).Abs( )

E um método com um tipo de receptor *TwoInts like AddThem ( ) pode ser chamado em um valor do tipo endereçável TwoInts, não há engano automática.

Assim two2.AddThem ( ) pode ser usado em vez de (&two2).AddThem( )

Métodos em valores e ponteiros chamada:

Pode haver métodos ligados ao tipo, e outros métodos anexados a um ponteiro para o tipo.Mas não importa:. Se para um tipo T um método Meth( ) existe em *T e t é uma variável do tipo T,

então t.Meth ( ) é automaticamente traduzido para o (& t).Meth( )Métodos de ponteiro e valor tanto pode ser chamado em valores de ponteiro ou não-ponteiro, este é

ilustrado no programa seguinte, onde a lista de tipo tem um método Len ( ) sobre o valor e um método Append ( ) em um ponteiro para lista, mas , vemos que ambos os métodos podem ser chamados de variáveis de ambos os tipos.

package mainimport ( “fmt”)type List [ ]intfunc (l List) Len( ) int { return len(l) }func (l *List) Append(val int) { *l = append(*l, val) }func main( ) {

var lst List lst.Append(1) fmt.Printf(“%v (len: %d)\n”, lst, lst.Len( )) / / [1] (len: 1) plst := new(List) plst.Append(2) fmt.Printf(“%v (len: %d)\n”, plst, lst.Len( )) / / &[2] (len: 1)

}

Métodos e campos não-exportados

Considere o começo de uma pessoa no pacote person2.go: o tipo de pessoa é claramente exportado, mas os seus campos não são! Por exemplo, a declaração em p.FirstName use_person2.go é um erro. Como podemos mudar, ou mesmo ler o nome de um objeto Person em outro programa?

Isto é conseguido por uma técnica bem conhecida de OO-idiomas: proporcionar getter- e métodos setters FirstName e setFirstName. Para o método setter que usamos o conjunto de prefixo, para o método getter só usamos o nome do campo.

package persontype Person struct {

firstName stringlastName string

}

func (p *Person) FirstName( ) string { return p.firstName

}

func (p *Person) SetFirstName(newName string) {

Page 312: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

p.firstName = newName}

Outro Exemple:

package mainimport (

“fmt” “./person” / / Pacote no mesmo mapa

)

func main( ) { p := new(person.Person)

/ / Erro: p.FirstName indefinido/ / (Não pode se referir ao campo não exportadas ou método nome) / / P.FirstName = "Eric"

p.SetFirstName(“Eric”) fmt.Println(p.FirstName( )) / / Output: Eric

}

Acesso concorrente aos objetos:

Não deveria ser possível que os campos (propriedades) de um objecto pode ser alterado por dois ou mais segmentos diferentes ao mesmo tempo. Se isso pode ocorrer em seu aplicativo, em seguida, a fim de fazer acces simultâneos seguro você pode usar os métodos da sincronização de pacotes.

Métodos em tipos de embutidos e herança

Quando um tipo anônimo é incorporado em uma estrutura, os métodos visíveis desse tipo são incorporados como bem de fato, o tipo externa herda os métodos: ao subtipo alguma coisa, você coloca o tipo de pai dentro do subtipo. Este mecanismo oferece uma maneira simples de imitar alguns dos efeitos da subclasse e herança encontrada em OO-línguas clássicas, mas também é muito análogo aos mixins de Ruby. Aqui está um exemplo ilustrativo: suponha que temos um tipo de interface do motor, e um carro tipo struct que contém um campo anônimo de Motor:

type Engine interface { Start( ) Stop( )

}type Car struct { Engine}

Poderíamos, então, construir o seguinte código:

func (c *Car) GoToWorkIn { / / Pega no car c.Start ( ); / / Unidade de trabalho c.Stop ( ); / / Sair do car}

No seguinte exemplo completo method3.go é mostrado que um método em um struct incorporado pode ser chamado diretamente em uma instância do tipo de incorporação.

package main

Page 313: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

import (“fmt”“math”

)type Point struct {

x, y float64}func (p *Point) Abs( ) float64 {

return math.Sqrt(p.x*p.x + p.y*p.y)}type NamedPoint struct {

Point name string

}func main( ) {

n := &NamedPoint{Point{3, 4}, “Pythagoras”} fmt.Println(n.Abs( )) / / prints 5

}

Embedding injeta campos e métodos de um tipo existente em um outro tipo: métodos associados com o campo anônimo são promovidos para tornar-se métodos do tipo delimitador. É claro que um tipo pode ter métodos que actuam apenas sobre as variáveis desse tipo, e não em variáveis do 'pai' tipo incorporado.

Também substituindo (assim como com campos) é implementado para métodos: um método no tipo de incorporação com o mesmo nome de um método em um tipo de embutido substitui isso temos apenas acrescentado:

func (n *NamedPoint) Abs( ) float64 {return n.Point.Abs( ) * 100.}

E agora a linha: fmt.Println (n.Abs ( )) imprime 500.

Porque um struct pode incorporar vários tipos anônimos, temos na verdade uma versão simples de herança múltipla, como em: type Child struct { Father; Mother }

Estruturas incorporação estruturas do mesmo pacote tem acesso total a um dos campos e métodos mais.

Como incorporar a funcionalidade em um tipo

Existem basicamente duas maneiras de fazer isso:

A agregação (ou composição): incluir um campo chamado do tipo da funcionalidade desejadaB Incorporação: Incorporar (anonimamente) o tipo de funcionalidade desejado.

Para torná-lo concreto suponha que temos um tipo de cliente e queremos incluir uma funcionalidade de registo com um tipo de log, que simplesmente contém uma mensagem acumulada (é claro que isso poderia ser elaborado). Se você quiser equipar todos os seus tipos de domínio com uma capacidade de registro, você implementa tal Log e adicioná-lo como um campo para o seu tipo, bem como um método de Log ( ) retornar uma referência a este registo.

Exemplo parte A

package mainimport (

“fmt”)

Page 314: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

type Log struct {

msg string}type Customer struct {Name stringlog *Log}func main( ) {

c := new(Customer) c.Name = "Minha Casa" c.log = new (Log) c.log.msg = "1 – Minha Vida" / / Mais curto: c := &Customer{“Minha Casa”, &Log {"! 1 – Minha Vida"}} / / Fmt.Println (c) / / & {Minha Caas 1 – Minha Vida} c.Log( ).Add ("2 - Depois de mim, o mundo será um lugar melhor!") / / Fmt.Println (c.log) fmt.Println (c.Log ( ))}func (l * Log) Adicionar (s string) { l.msg + = "\ n" + s}func (l * Log) String ( ) string { return l.msg}func (c *Customer) Log( ) *Log { return c.log}

/ * Saída do log:1 – Minha Vida2 - Depois de mim, o mundo será um lugar melhor!* /

Exemplo parte B

package mainimport ( “fmt”)type Log struct {

msg string}type Customer struct { Name stringLog}func main( ) {

c := &Customer{“Minha Casa”, Log{“1 – Minha Vida”}} c.Add(“2 - Depois de mim, o mundo será um lugar melhor!”) fmt.Println(c)

}func (l *Log) Add(s string) {

l.msg += “\n” + s}func (c *Customer) String( ) string {

return c.Name + “\nLog:” + fmt.Sprintln(c.Log)}func (l *Log) String( ) string {

return l.msg

Page 315: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}

/ * Saída:Minha CasaLog: {1 – Minha Vida2 - Depois de mim, o mundo será um lugar melhor}!* /

O tipo embutido não precisa um ponteiro, o cliente não precisa de um método Add mais, porque ele usa o método de Log, o Cliente pode ter seu próprio String-método e usando nela a sequência log ( ) método.

Isto também funciona se o tipo incorporado em si incorpora um outro tipo, e os métodos do tipo incorporado pode ser usado directamente pelo tipo de incorporação.

Assim, uma boa estratégia é construir pequenas tipos reutilizáveis como uma caixa de ferramentas para a composição dos próprios tipos de domínio.

Herança múltipla

Herança múltipla é a capacidade de um tipo para obter os comportamentos de mais de uma classe pai. Em linguagens OO clássicos que normalmente não é implementada (exceções são C + + e Python), porque em hierarquias baseadas em classes introduz complexidades adicionais para o compilador. Mas em Go ele pode ser implementado simplesmente incorporando todos os tipos necessários 'pai' do tipo em construção.

Como um exemplo, suponha que você quer ter um cameraphone tipo, com o qual você pode ligar para ( ) e com o qual você pode TakeAPicture ( ), mas o primeiro método pertence ao tipo de telefone, eo segundo ao tipo de câmera.

A incorporação de ambos os tipos resolve o problema, como é ilustrado no seguinte programa:

package mainimport “fmt”type Camera struct { }func (c *Camera) TakeAPicture( ) string { return “Click”}type Phone struct { }func (p *Phone ) Call( ) string { return “Ring Ring”}/ / Herança múltiplatype CameraPhone struct {

Camera Phone

}func main( ) {

cp := new(CameraPhone) fmt.Println(“Our new CameraPhone exhibits multiple behaviors ...”) fmt.Println(“It exhibits behavior of a Camera: “, cp.TakeAPicture( )) fmt.Println(“It works like a Phone too: “, cp.Call( ))

}

/ * Saída:Our new CameraPhone exhibits multiple behaviors ...It exhibits behavior of a Camera: ClickIt works like a Phone too: Ring Ring* /

métodos universais e método de nomeação

Page 316: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Na programação uma série de operações básicas aparecem uma e outra vez, como abertura, fechamento, leitura, escrita, classificação, etc Além disso, eles têm um significado geral para eles: abertura pode ser aplicado para um arquivo, uma conexão de rede, uma conexão de banco de dados , etc Os detalhes da implementação são em cada caso muito diferente, mas a idéia geral é a mesma. Em Go esta é aplicada extensivamente na biblioteca padrão, através da utilização de interfaces , em que tais métodos genéricos obter nomes canônicos como Open ( ), Read ( ), Write ( ), etc Se você quiser escrever idiomática Go , você deve seguir esta convenção, dando a seus métodos, onde os mesmos nomes e as assinaturas apropriadas como

esses métodos "canônicos". Isso faz com que o software Go mais consistente e legível. Por exemplo: se você precisa de um método convert-to-string, nomeá o String ( ) e não ToString ( ).

Comparação entre tipos e métodos e outras linguagens orientadas a objeto Go.

Métodos em linguagens OO como C + +, Java, C # ou Ruby são definidas no contexto de classes e herança: quando um método é chamado em um objeto, o tempo de execução vê se o seu minério de classe qualquer de suas superclasses ter uma definição para esse método, caso contrário, resultará em uma exceção.

Em Go tal uma hierarquia de herança não é de todo necessário: se o método é definido para esse tipo pode ser invocado, independente de haver ou não o método existe para outros tipos, por isso, nesse sentido, há uma maior flexibilidade.

GO não exigem uma definição de classe explícita como Java, C + +, C #, etc fazer. Em vez disso, uma "classe" é implicitamente definido, fornecendo um conjunto de métodos que operam em um tipo comum. Este tipo pode ser um struct ou qualquer outro tipo definido pelo usuário.

Por exemplo: dizer que gostaria de definir o nosso próprio tipo Integer para adicionar algumas possíveis métodos para trabalhar com números inteiros, como um tostring-conversão. Em Go que definiria isso como:

type Integer intfunc (i *Integer) String( ) string { return strconv.Itoa(i)}

Em Java ou C # o tipo ea função seriam colocados juntos em um Integer classe; no Ruby você pode simplesmente escrever o método do tipo int básica.

Resumido: em Go tipos são basicamente classes (dados e métodos associados). GO não sabe como herança linguagens OO orientada classe. Herança tem duas vantagens principais: a reutilização de código e polimorfismo.

A reutilização de código em Go é conseguido através da composição e da delegação, e polimorfismo através do uso de interfaces: ele implementa o que às vezes é chamado de programação de componentes.

Muitos desenvolvedores dizem que as interfaces da Go fornecer um comportamento polimórfico mais potente e ainda mais simples do que a herança de classe.

Observação:Se você realmente precisa de mais recursos de OO, dê uma olhada no pacote gosma ("Go

Programação Orientada a Objetos") de Scott Pakin (https:/ /github.com/losalamos/goop): fornece Go com objetos de estilo JavaScript (objetos com base em protótipo), mas suporta herança múltipla e expedição, dependente do tipo de modo que você provavelmente pode implementar a maioria de suas construções favoritas de outras linguagens de programação.

A String ( )-método e formato especificadores para um tipo

Quando você define um tipo com uma série de métodos, as chances são que você vai querer fazer uma seqüência de caracteres de saída personalizada para ele com uma String (método), em outras palavras: uma saída legível e impressão. Isto é porque se string ( ) é definido por um determinado tipo, então este método será utilizado em fmt.Printf ( ) para produzir o padrão de saída: o que é produzido com o

Page 317: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

especificador de formato % v Também fmt.Print ( ) e fmt.Println ( ) usará automaticamente o método ( ) da cadeia.

package mainimport (

“fmt” “strconv”

)type TwoInts struct {

a int b int

}func main( ) {

two1 := new(TwoInts) two1.a = 12 two1.b = 10 fmt.Printf(“two1 is: %v\n”, two1) / / output: two1 is: (12 / 10)

fmt.Println(“two1 is:”, two1) / / output: two1 is: (12 / 10) fmt.Printf(“two1 is: %T\n”, two1)

/ / output: two1 is: *main.TwoInts fmt.Printf(“two1 is: %#v\n”, two1)

/ / output: &main.TwoInts{a:12, b:10}}func (tn *TwoInts) String( ) string {

return “(“+ strconv.Itoa(tn.a) +” / “+ strconv.Itoa(tn.b) + “)”}

Assim, sempre que você estará usando extensivamente um certo tipo que você fez a si mesmo, é conveniente fazer uma String( )-method para isso Vemos também que o especificador de formato %T nos dá a especificação do tipo completo % # v nos dá uma saída completa da instância com seus campos (que também pode ser útil na geração de código de programação Go).

Observação:

Não cometa o erro de definir String ( ) em termos de si mesmo, como no seguinte snippet. Em seguida, o programa faz uma recursão infinita (TT.String ( ) chama fmt.Sprintf que chama TT.String ( ) ...) e rapidamente dá um erro de falta de memória:

type TT float64 func (t TT) String( ) string { return fmt.Sprintf(“%v”, s) } t.String( )

A coleta de lixo e SetEstreitolizer

O desenvolvedor Go não tem que codificar a liberação de memória para as variáveis e estruturas que não são mais utilizados no programa. Um processo separado no tempo de execução Go, o coletor de lixo, cuida disso. Ele começa agora e então, procura por variáveis que não são mais indicados e libera essa memória. Funcionalidade em relação a este processo pode ser acessado através do pacote de tempo de execução.

A coleta de lixo pode ser chamado explicitamente chamando function runtime.GC( ), mas isso só é útil em casos raros, por exemplo, quando os recursos de memória são escassos, um grande pedaço de memória puderam ser imediatamente libertado nesse ponto na execução, ea programa pode ter uma redução momentânea no desempenho (por causa do processo de coleta de lixo).

Se você quiser saber o estado da memória atual, use:fmt.Printf(“%d\n”, runtime.MemStats.Alloc/1024)Suponha que uma ação especial deve ser tomado imediatamente antes de um objeto obj é removido

Page 318: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

da memória, como escrever para um arquivo de log. Isto pode ser conseguido chamando a função:runtime.SetEstreitolizer(obj, func(obj *typeObj))onde func(obj * typeObj) é uma função que leva um ponteiro-parâmetro do tipo de obj que executa a

ação adicional. função também pode ser uma função anônima.SetEstreitolizer não executa quando o programa chega ao fim normal ou quando ocorre um erro, antes

que o objeto foi escolhido pelo processo de coleta de lixo a ser removido.

O que é uma interface?

Pense na primeira imagem que vem à sua mente quando falamos esta palavra: interface. Certamente, existe uma grande possibilidade de você ter pensado em uma janela/formulário para a interação com os usuários de seu sistema. Contudo, podemos Go mais a fundo e também imaginar os objetos de nossa aplicação interagindo uns com os outros. Estes, por sua vez, precisam se conhecer para então saber que mensagens poderão trocar. É aí que entram as interfaces. Além das já citadas interações com usuário e entre objetos, programas inteiros também podem se comunicar e peças de hardware precisam se encaixar perfeitamente. Com isso, fica fácil imaginar diversas situações para o uso de interfaces.

Podemos visualizar os objetos de nossa aplicação como instâncias de uma classe na memória e dividi-los em duas partes: sua visualização externa e a própria implementação de seus métodos. Vamos então conceitualizá-las como um contrato entre duas partes. Se determinado objeto declara que implementa uma interface, ele a deve seguir à risca, implementando tudo o que for estipulado por este “acordo”. Da mesma maneira, os outros objetos poderão ter certeza de que as mensagens enviadas a ele serão correspondidas. E o mais importante: saberão quais operações poderão ser solicitadas.

Tente fazer uma relação desses objetos com um programa e sua interface gráfica. A intenção do desenho de um formulário é a de mostrar quais operações podem ser executadas sobre tal aplicação. Expondo-as de maneira clara para quem estiver utilizando o sistema.

E quais as vantagens do uso desse conceito em meus objetos? Go é uma linguagem fortemente tipada. Isso significa que, quando um método é chamado, já sabemos previamente quais os seus parâmetros e seu tipo de retorno.

Se declararmos uma variável em nosso código, estaremos certos de que poderemos chamar qualquer método disponibilizado pelo objeto que a ela for associado. Ou seja, declarar uma classe que implementa X significa dizer que todos os métodos dessa interface X estarão presentes para Y. Como podemos entender uma interface X ou Y poderia ter ainda diversos outros métodos próprios .

Neste ponto, já podemos apontar uma grande utilidade para esse conceito. Imagine a implementação de um grande sistema. Quando dois programadores ou pares iniciam a codificação de módulos separados e interligados, eles podem estabelecer previamente um “contrato” de comunicação. Deste modo, quem programa o módulo A, saberá que o módulo B implementa a interface X, portanto, terá certeza das mensagens que poderão ser enviadas. E mais importante do que isso, terá código compilável e receberá ajuda do tipo code insight ao manipular os fontes.

Mas o que há de tão especial em IInterface? Até o momento, a única utilidade prática das interfaces está na garantia de que determinados métodos estão presentes nas classes. Veja que conseguimos driblar a falta da herança múltipla apenas com o uso de interfaces. Este é um dos principais pontos de uso do conceito abordado, que está presente em quase todas as linguagens que nos disponibilizam a programação orientada a objetos. Diferentemente da herança múltipla, que é muito difícil de ser implementada e controlada.

Um projeto de sistema orientado a objetos pode apresentar muitos pontos complexos a serem tratados. Como percebemos, as interfaces nos permitem muita flexibilidade tanto na hora do design como da implementação.

Go não é uma linguagem OO "clássico": ele não sabe o conceito de classes e herança. Uma interface define um conjunto de métodos (o conjunto do método), mas estes métodos não contêm código: eles não são implementados (eles são abstratos). Também uma interface não pode conter variáveis. Uma interface é declarado no formato:

type Namer interface { Method1(param_list) return_type Method2(param_list) return_type

Page 319: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

...}onde Namer é um tipo de interface.

O nome de uma interface é formada pelo nome do método, mais o [e] r sufixo, como impressoras, leitor, escritor, Logger, conversor, etc, dando assim um substantivo ativo como um nome. Uma alternativa menos utilizados (quando .. er não é tão apropriado) é acabar com poder como na recuperável, ou para iniciá-lo com um I (Mais como in. NET ou Java).

Interfaces em Go são curtos, eles geralmente têm de 0 máximo três métodos.Ao contrário da maioria das linguagens OO, em interfaces de Go pode ter valores, uma variável do tipo

de interface ou um valor de interface: var ai Namerai é uma estrutura de dados multiword com um valor não inicializado de zero. Allthough não

completamente a mesma coisa, que é, em essência, um ponteiro. Então ponteiros para fazer a interface valores são ilegais, pois eles seriam completamente inúteis e dar origem a erros no código.

Sua mesa de método ponteiros é construir através da capacidade de execução reflexão.Tipos (como estructs) pode ter o conjunto método da interface implementada, a aplicação contém para

cada código verdadeiroo método de como agir em uma variável desse tipo: eles implementam a interface, o conjunto método constitui a interface desse tipo. Uma variável de um tipo que implementa a interface pode ser atribuída a ai (o valor do receptor), então o método de mesa tem ponteiros para os métodos de interface implementadas. Ambos de mudança de curso, quando uma variável de outro tipo (que também implementa a interface) é atribuído a ai.

Um tipo não tem que declarar explicitamente que implementa uma interface: interfaces são satisfeitas de forma implícita.

Vários tipos podem implementar a mesma interface.Um tipo que implementa uma interface pode também ter outras funções.Um tipo pode implementar várias interfaces.Um tipo de interface pode incluir uma referência a uma instância de qualquer um dos tipos que

implementam a interface (Uma interface tem o que é chamado um tipo dinâmico).Mesmo que a interface foi definida mais tarde do que o tipo, em um pacote diferente, compilados

separadamente: se o objeto implementa os métodos citados na interface, em seguida, ele implementa a interface. Todas estas propriedades permitem uma grande flexibilidade.

package mainimport “fmt”type Shaper interface { Area( ) float32type Square struct {

side float32}func (sq *Square) Area( ) float32 { return sq.side * sq.side}func main( ) {

sq1 := new(Square) sq1.side = 5 / / var areaIntf Shaper / / areaIntf = sq1 / / Mais curto, sem declaração separada: / / areaIntf := Shaper(sq1) / /Ou ainda: areaIntf := sq1 fmt.Printf(“The square has area: %f\n”, areaIntf.Area( ))

}

Saída: O quadrado tem área: 25.000000

O programa define uma estrutura quadrada e um Shaper interface, com um método Area( ).Em main( ) uma instância de Praça é construída. Fora da principal, temos um método Area( ) com um

tipo de receptor de Square, onde a área de um quadrado é calculado: a struct Square implementa o Shaper interface.

Page 320: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Devido a isso, podemos atribuir uma variável do tipo Square para uma variável do tipo de interface:areaIntf = sq1Agora, a variável de interface contém uma referência para a variável Square e através dela podemos

chamar o método Area( ) em Square. Claro que você pode chamar o método imediatamente na instância Square sq1.Area( ), mas a novidade é que podemos chamá-lo na instância interface, assim generalizando a chamada. A variável de interface contém tanto o valor do exemplo receptor e um ponteiro para o método adequado de uma tabela método.

Esta é a versão de Go de polimorfismo, um conceito bem conhecido em software OO: o método correto é escolhido de acordo com o tipo de corrente, ou colocar de outra forma: um tipo parece apresentar comportamentos diferentes quando associada a diferentes instâncias.

Se Square não teria uma implementação de Area ( ), gostaríamos de receber o erro de compilador muito clara:

não pode usar sq1 (type *Square) como tipo Shaper na atribuição:*Square não implementar Shaper (faltando método Area)

O mesmo erro ocorreria se Shaper tinha outro método Perímetro( ), e da Praça não teria uma implementação para que, mesmo que Perímetro ( ) não foi chamado em uma instância Square.

Sabemos expandir o exemplo com um retângulo tipo que também implementa Shaper. Podemos agora fazer uma array com elementos do tipo Shaper, e mostrar polimorfismo em ação, usando um para a faixa nele e chamando Area ( ) em cada item:

Listagem 11.2-interfaces_poly.go:

package mainimport “fmt”type Shaper interface {

Area( ) float32}type Square struct {

side float32}func (sq *Square) Area( ) float32 {

return sq.side * sq.side}type Rectangle struct { length, width float32}func (r Rectangle) Area( ) float32 { return r.length * r.width}func main( ) { r := Rectangle{5, 3} / / Área ( ) do retângulo precisa de um valorq := &Square{5 / / Area ( ) da Square (Praça) precisa de um ponteiro / / shapes := [ ]Shaper{Shaper(r), Shaper(q)} / / Ou mais curto: shapes := [ ]Shaper{r, q, c} fmt.Println(“Looping through shapes for area ...”) for n, _ := range shapes { fmt.Println(“Shape details: “, shapesArr[n]) fmt.Println(“Area of this shape is: “, shapes[n].Area( )) }}

/ * Saída:Looping through shapes for area ...Shape details: {5 3}Area of this shape is: 15Shape details &{5}Area of this shape is: 25* /

Page 321: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

No ponto de chamar formas [n]. Area ( )) só sabemos que este é um objeto Shaper, sob a capa "morphs" em um quadrado ou um retângulo e se comporta de acordo.

Talvez agora você pode começar a ver como as interfaces podem produzir um código mais limpo, mais simples e mais escalável.

Aqui está um outro exemplo mais concreto: temos 2 tipos stockPosition e carro, ambos têm um método getValue ( ); percebendo que podemos definir uma interface valiosa com este método. E o que podemos definir métodos que levam um parâmetro do tipo valioso e que são utilizados por todos os tipos que

package mainimport “fmt”type stockPosition struct { ticker string sharePrice float32}/ * Método para determinar o valor de uma posição de estoque * /func (s stockPosition) getValue( ) float32 { return s.sharePrice * s.count} type car struct { make string model string price float32}/ * Método para determinar o valor de um carro * /func (c car) getValue( ) float32 { return c.price}/ * Contrato que define as coisas diferentes que têm valor * /type valuable interface { getValue( ) float32}/ * Qualquer coisa que satisfaça a interface de "valioso" é aceito * /func showValue(asset valuable) { fmt.Printf(“Value of the asset is %f\n”, asset.getValue( ))}func main( ) { var o valuable = stockPosition{ “GOOG”, 577.20, 4 } showValue(o) o = car{ “BMW”, “M3”, 66500 } showValue(o)}

/ *Saída:Value of the asset is 2308.800049Value of the asset is 66500.000000* /

Um exemplo da biblioteca padrão: O pacote io contém um tipo de interface do Leitor:

type Reader interface {Read(p [ ]byte) (n int, err error)}

Se definirmos a r variável como: var r io.Readerem seguida, o seguinte é o código correto:

r = os.Stdinr = bufio.NewReader(r)

Page 322: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

r = new(bytes.Buffer)f, _ := os.Open(“test.txt”)r = bufio.NewReader(f)

porque o lado direito objetos cada implementar um método Read( ) com a mesma assinatura exata.O tipo estático de r é io.Reader.

Observação:

Por vezes, a interface de palavra também é utilizada de um modo ligeiramente diferente: visto a partir do ponto de vista de um determinado tipo, a interface desse tipo é o conjunto de métodos exportados definidos para o tipo, sem que tenha de ser um tipo de interface explícita definido com estes métodos.

Interface do incorporação (s)

Uma interface pode conter o nome de um (ou mais) outra interface (s), o que equivale a enumerar explicitamente os métodos da interface incorporado na interface contendo.

Por exemplo a interface do arquivo contém todos os métodos de ReadWrite e bloqueio, além de um método Close ( ).

type ReadWrite interface { Read(b Buffer) bool Write(b Buffer) bool

}type Lock interface {

Lock( ) Unlock( )

}type File interface {

ReadWrite Lock Close( )

}

Como detectar e converter o tipo de uma variável de interface: tipo asserções

Uma variável de tipo de interface variável pode conter um valor de qualquer tipo, é preciso ter um meio de detectar este tipo dinâmico, que é o tipo real do valor armazenado na variável em tempo de execução. O tipo de dinâmica pode variar durante a execução, mas é sempre atribuído ao tipo da própria variável interface.

Em geral, podemos testar se Vari contém em um determinado momento uma variável do tipo T com o teste de assertion tipo:

v := varI.(T) / / Assertion tipo desmarcadavari deve ser uma variável de interface, se não o compilador sinaliza o erro: inválidovarI.(T) (tipo não de interface (type of varI) à esquerda)

A assertion tipo pode não ser válido, o compilador faz o máximo possível para ver se a conversão é válida, mas não pode prever todos os casos possíveis. Se essa conversão falhar durante a execução do programa de um erro de execução ocorre! A maneira mais segura é usar a seguinte forma:

if v, ok := varI.(T); ok { / / Verificado type assertion Process(v) return}/ / varI não é do tipo T

Page 323: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Se essa conversão é válida, v Irá conter o valor da variável convertidos para o tipo T e ok será verdadeiroa, caso contrário, v é o valor zero para T e ok é falsa, então não há erro de execução ocorre!

! Sempre use a vírgula, forma ok para o tipo afirmações!Na maioria dos casos você gostaria de testar o valor de ok em um caso, então, é mais conveniente

usar a forma:

if v, ok := varI.(T); ok { / / ...}

Nesta forma de sombreamento a variável Vari dando Vari e v o mesmo nome às vezes é feito.Um exemplo pode ser visto na Listagem

O detector de

O tipo de uma variável de interface também pode ser testada com um tipo especial de switch: o switch tipo:

switch t := areaIntf.(type) {case *Square:fmt.Printf(“Type Square %T with value %v\n”, t, t)case *Circle:fmt.Printf(“Type Circle %T with value %v\n”, t, t)case float32:fmt.Printf(“Type float32 with value %v\n”, t)case nil:fmt.Println(“nil value: nothing to check?”)default:fmt.Printf(“Unexpected type %T”, t)}

Saida : Type Square *main.Square with value &{5}

A variável t recebe valor e tipo de areaIntf. Todos os tipos listados (exceto nil) têm de implementar a interface (Shaper, neste caso), se o tipo atual é nenhum dos casos-tipos, a cláusula default é executado.

Fallthrough não é permitido. Com um type-switch uma análise do tipo de tempo de execução pode ser feito. Claro que todos os tipos internos como int, bool e string também pode ser testado em um switch tipo.

Se você só precisa testar o tipo switch. e não precisa do valor, a atribuição pode ser deixado de fora, como:

switch areaIntf.(type) {case *Square:

fmt.Printf(“Type Square %T with value %v\n”, t, t)case *Circle:

fmt.Printf(“Type Circle %T with value %v\n”, t, t) ...

default: fmt.Printf(“Unexpected type %T”, t)

}

No seguinte trecho de código de uma função tipo classificador é mostrado que aceita uma array com um número variável de argumentos de qualquer tipo, e que executa algo de acordo com o tipo determinado:

func classifier(items ...interface{ }) { for i, x := range items { switch x.(type) {

Page 324: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

case bool: fmt.Printf(“param #%d is a bool\n”, i) case float64: fmt.Printf(“param #%d is a float64\n”, i) case int, int64: fmt.Printf(“param #%d is an int\n”, i) case nil: fmt.Printf(“param #%d is nil\n”, i) case string: fmt.Printf(“param #%d is a string\n”, i) default: fmt.Printf(“param #%d’s type is unknown\n”, i) } }}

Quando se tratar de dados de tipo desconhecido de testes de fontes externas tipo e conversão para tipos Go de dados pode ser muito útil, por exemplo, a análise de dados que são JSON ou codificados em XML.

Testando se um valor implementa uma interface

Este é um caso especial do tipo de assertion: suponha que v é um valor e queremos testar se ele implementa a interface Stringer, isso pode ser feito da seguinte forma:

type Stringer interface { String( ) string }if sv, ok := v.(Stringer); ok {

fmt.Printf(“v implements String( ): %s\n”, sv.String( ));}

Esta é a forma como as funções de impressão verificar se o tipo pode imprimir-se. Uma interface é uma espécie de contrato que o tipo de execução. Interfaces descrever o comportamento de tipos, o que eles podem fazer. Eles completamente separar a definição do que um objeto pode fazer a partir de como ele faz isso, permitindo implementações distintas de se fazer representar em momentos diferentes pela mesma variável de interface, que é o polimorfismo é essencialmente.

Escrevendo funções para que eles aceitar uma variável de interface como parâmetro torna mais geral.!Use interfaces para tornar seu código de aplicação mais geral!Isso também é aplicado onipresente no código da biblioteca padrão. É impossível compreender como é

construir sem uma boa compreensão do conceito de interface.

método usando conjuntos com interfaces

vimos que os métodos de variáveis na verdade não fazem distinção entre os valores ou ponteiros. Ao armazenar um valor em um tipo de interface é um pouco mais complicado, porque um valor concreto armazenado em uma interface não é endereçável, mas felizmente os flags do compilador um erro no uso inadequado.Considere o seguinte programa:

package mainimport (

“fmt”)type List [ ]intfunc (l List) Len( ) int { return len(l) }func (l *List) Append(val int) { *l = append(*l, val) }type Appender interface { Append(int)}func CountInto(a Appender, start, end int) { for i := start; i <= end; i++ {

a.Append(i) }}

Page 325: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

type Lener interface { Len( ) int

}func LongEnough(l Lener) bool {

return l.Len( )*10 > 42}func main( ) {/ / Um valor nú var lst List/ / Erro do compilador:/ / Não pode usar lst type List) como tipo Appender no argumento da função:/ / Lista de não implementar Appender (Append método requer ponteiro / / Receptor) / / CountInto (lst, 1, 10) if LongEnough(lst) / / VÁLIDO: tipo de receptor Idêntico fmt.Printf(“- lst is long enough”) } / / Um valor de ponteiro plst := new(List) CountInto(plst, 1, 10) / / VÁLIDO: tipo de receptor Idêntico if LongEnough(plst) { / / VÁLIDO: a lista * pode ser desreferenciado para o receptor fmt.Printf(“- plst is long enough”) / / - Plst2 é longa enoug }}

Discussão:

CountInto chamado com o valor lst dá um erro do compilador porque CountInto leva uma Appender, e Append( ) só é definido para um ponteiro. LongEnough no valor obras lst porque Len( ) é definida em um valor.

CountInto chamado com o ponteiro plst funciona porque CountInto leva uma Appender e Append( ) é definida por um ponteiro. LongEnough no ponteiro plst funciona porque um ponteiro pode ser desreferenciado para o receptor.

Resumido: quando você chamar um método em uma interface, ele deve ou ter um tipo de receptor idêntico ou deve ser diretamente perceptível a partir do tipo de concreto: P

• métodos de ponteiro pode ser chamado com ponteiros.• métodos de Valor pode ser chamada com valores.• métodos Valor receptor pode ser chamada com valores de ponteiro, pois eles podem ser

desreferenciado primeiro.• métodos Pointeiro receptor não pode ser chamada com valores, no entanto, porque o valor

armazenado dentro de uma interface não tem endereço.

Ao atribuir um valor a uma interface, o compilador garante que todos os possíveis métodos de interface pode realmente ser chamado nesse valor, e, assim, tentar fazer uma atribuição indevida falhará na compilação.

exemplo: triagem com a interface Sorter

Um bom exemplo vem da própria biblioteca Go, ou seja, o tipo de pacote. Para classificar uma coleção de números e strings, você só precisa do número de elementos Len( ), uma maneira de comparar itens i e j Less(i, j) e um método para trocar itens com índices i e j de swap(i, j )

A função Ordenar em espécie tem um algoritmo que utiliza apenas estes métodos em um conjunto de dados de coleta (para implementá-lo, usamos aqui uma espécie de bolha, mas qualquer tipo algoritmo poderia ser utilizado.):

Page 326: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func Sort(data Sorter) { for pass:=1; pass < data.Len( ); pass++ {

for i:=0; i < data.Len( ) - pass; i++ {if data.Less(i+1, i) {

data.Swap(i, i+1) } } }}

Ordenar por isso pode aceitar um parâmetro geral de um classificador tipo de interface que declara esses métodos:

type Sorter interface { Len( ) int Less(i, j int) bool Swap(i, j int)

}

O tipo int em Sorter não significa que os dados de cobrança deve conter ints, I e J são índices inteiros, e o comprimento é também um inteiro. Agora, se queremos ser capazes de classificar um array de inteiros, tudo o que precisamos fazer é definir um tipo e implementar os métodos da interface:

type IntArray [ ]intfunc (p IntArray) Len( ) int { return len(p) }func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

Aqui está o código para chamar a funcionalidade de classificação em um caso concreto:

dados: := [ ]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}a := sort.IntArray(data) / /conversion to type IntArray from package sortsort.Sort(a)

O código completo de trabalho podem ser encontrados em sort.go e sortmain.go.

Para ilustrar o poder do conceito, o mesmo princípio é aplicado para uma variedade array of floats, de strings, e uma array de estruturas dayArray que representam os dias da semana.

package sorttype Sorter interface {

Len( ) int Less(i, j int) bool Swap(i, j int)

}func Sort(data Sorter) {

for pass:=1; pass < data.Len( ); pass++ {for i:=0; i < data.Len( ) - pass; i++ {

if data.Less(i+1, i) {data.Swap(i, i+1)

} } }}func IsSorted(data Sorter) bool {

n := data.Len( ) for i := n - 1; i > 0; i-- {

if data.Less(i, i-1) {return false

}

Page 327: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

} return true

}

/ / Tipos conveniêntes para os casos comunstype IntArray [ ]intfunc (p IntArray) Len( ) int { return len(p) }func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }type StringArray [ ]stringfunc (p StringArray) Len( ) int { return len(p) }func (p StringArray) Less(i, j int) bool { p[i], p[j] = p[j], p[i] }type StringArray [ ]stringfunc (p StringArray) Len( ) int { return len(p) }func (p StringArray) Less(i, j int) bool { return p[i] < p[j] }func (p StringArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }func SortInts(a [ ]int { Sort(IntArray(a)) }func SortStrings(a [ ]string) { Sort(StringArray(a)) }

func IntsAreSorted(a [ ]int) bool { return IsSorted(IntArray(a)) }func StringsAreSorted(a [ ]string) bool { return IsSorted(StringArray(a)) }

Continuando:

package mainimport (

“fmt” “./sort”

)func ints( ) {data := [ ]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}

a := sort.IntArray(data) / /conversion to type IntArray sort.Sort(a) if !sort.IsSorted(a) {

panic(“fail”) } fmt.Printf(“The sorted array is: %v\n”, a)

}func strings( ) {

data := [ ]string{“monday”, “friday”, “tuesday”, “wednesday”, “sunday”, “thursday”, “”, “saturday”} a := sort.StringArray(data) sort.Sort(a) if !sort.IsSorted(a) {

panic(“fail”) } fmt.Printf(“The sorted array is: %v\n”, a)

}type day struct {

num int shortName string longName string

}type dayArray struct {

data [ ]*day}func (p *dayArray) Len( ) int { return len(p.data) }func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num }

Page 328: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func (p *dayArray) Swap(i, j int) { p.data[i], p.data[j] = p.data[j],p.data[i] }func days( ) {

Sunday := day{0, “SUN”, “Sunday”} Monday := day{1, “MON”, “Monday”} Tuesday := day{2, “TUE”, “Tuesday”} Wednesday := day{3, “WED”, “Wednesday”} Thursday := day{4, “THU”, “Thursday”} Friday := day{5, “FRI”, “Friday”} Saturday := day{6, “SAT”, “Saturday”} data := [ ]*day{&Tuesday, &Thursday, &Wednesday, &Sunday, &Monday, &Friday, &Saturday} a := dayArray{data} sort.Sort(&a) if !sort.IsSorted(&a) {

panic(“fail”) }for _, d := range data {fmt.Printf(“%s “, d.longName) } fmt.Printf(“\n”)

}func main( ) {ints( )strings( )days( )}

Saída:

The sorted array is: [-5467984 -784 0 0 42 59 74 238 905 959 7586 7586 9845]The sorted array is: [ friday monday saturday sunday thursday tuesday wednesday]Sunday Monday Tuesday Wednesday Thursday Friday Saturday

Observação:

panic ("falha") é uma maneira de parar o programa em uma situação que não poderia ocorrer em circunstâncias comuns ; que também poderia ter impresso uma mensagem e, em seguida, usado os.Exit (1) .

Este exemplo nos deu uma melhor visão do significado e uso de interfaces. Para classificar os tipos primitivos, sabemos que não temos de escrever esse código nós mesmos, a biblioteca padrão fornece para isso. Para a classificação geral do pacote de classificação define a

type Interface interface { Len( ) int Less(i, j int) bool Swap(i, j int)

}

que resume os métodos abstratos necessários para a classificação, a func Sort (interface de dados) que pode atuar em tal tipo. Estes podem ser usados na execução de triagem para outros tipos de dados. Na verdade isso é exatamente o que nós fizemos no exemplo acima, a utilização deste para ints e strings, mas também para uma dayArray tipo definido pelo usuário, para classificar uma array interna de strings.

segundo exemplo: Leitura e Escrita

A leitura ea escrita são atividades universais em software: a leitura e gravação de arquivos vem à mente em primeiro lugar, a leitura ea escrita de buffers (por exemplo, slices de bytes ou a strings), e para a

Page 329: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

entrada padrão, fluxos de saída e de erro, conexões de rede, tubos, etc, ou para os nossos próprios tipos personalizados. Para fazer com que a base de código o mais genérico possível, Go tem uma abordagem consistente para ler e gravar dados.

type Reader interface {Read(p [ ]byte) (n int, err error)

}type Writer interface {

Write(p [ ]byte) (n int, err error)}

Você pode ler e escrever em qualquer tipo, desde que o tipo fornece os métodos Read( ) e Write( ), necessária para satisfazer as interfaces de leitura e escrita. Para um objeto para ser lido deve satisfazer a interface io.Reader. Essa interface especifica um único método com assinatura, Read([ ]byte)(int, error). O método Read( ) lê os dados do objeto que ele é chamado em e coloca os dados lidos na slice byte dado. Ele retorna o número de bytes lidos e um objeto de erro que será nulo se não houve erro, ou io.EOF ("fim de arquivo") se não houve erro e ao estreitol da entrada foi atingido, ou algum outro não-nula valor se ocorrer um erro. Da mesma forma, para um objeto de poder ser escrito ele deve satisfazer a interface io.Writer. Essa interface especifica um único método com assinatura, Write ([ ] byte)(int, error)). O método Write( ) grava dados da slice byte dado no objeto o método foi chamado, e retorna o número de bytes escritos e um objeto de erro (que será nulo se não houve erro).

Readers e Writers io são unbuffered, o pacote bufio prevê as correspondentes operações de buffer e por isso são especialmente úteis para ler e escrever arquivos UTF-8 texto codificado.

Através da utilização, tanto quanto possível essas interfaces na assinatura de métodos, eles se tornam o mais genérico possível: cada tipo que implementa essas interfaces pode usar esses métodos. Por exemplo, a função que implementa um decodificador JPEG tem um leitor como um parâmetro, e, portanto, pode decodificar a partir do disco, conexão de rede, http compactado, etc

interface vazio

A interface vazia ou mínima não tem métodos e assim não faz qualquer exigência em tudo.type Any interface{ }Assim, qualquer variável, qualquer tipo implementa-lo (e não apenas os tipos de referência como o

objeto em Java / C #), e qualquer ou Qualquer é realmente um bom nome como apelido e abreviação!(É análogo ao objeto de classe em Java e C #, a classe base de todas as classes, assim Obj também

se encaixa.)A variável desse tipo de interface de var val interface{ } pode através de atribuição receber uma

variável de qualquer tipo:

package mainimport “fmt”var i = 5var str = “ABC”type Person struct {

name string age int

}type Any interface{ }func main( ) {

var val Any val = 5 fmt.Printf(“val has the value: %v\n”, val) val = str fmt.Printf(“val has the value: %v\n”, val) pers1 := new(Person) pers1.name = “Rob Pike” pers1.age = 55 val = pers1

Page 330: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

fmt.Printf(“val has the value: %v\n”, val) switch t := val.(type) { case int:

fmt.Printf(“Type int %T\n”, t)case string:

fmt.Printf(“Type boolean %T\n”, t)case bool:

fmt.Printf(“Type boolean %T\n”, t)case *Person:

fmt.Printf(“Type pointer to Person %T\n”, *t)default: fmt.Printf(“Unexpected type %T”, t) }}

Saida:val has the value: 5val has the value: ABCval has the value: &{Rob Pike 55}Type pointer to Person main.Person

Um int, uma string e uma instância a Person é atribuído a uma variável val interface. Um teste de switch-type para seu tipo. Cada interface { } variável ocupa duas palavras na memória: uma palavra para o tipo do que está contido, a outra palavra, quer para os dados contidos ou um ponteiro para ele.

Mostramos agora um exemplo de uso da interface vazio em um switch tipo combinada com uma função lambda:

package mainimport “fmt”type specialString stringvar whatIsThis specialString = “hello”func TypeSwitch( ) {

testFunc := func(any interface{ }) { switch v := any.(type) { case bool: fmt.Printf(“any %v is a bool type”, v) case int: fmt.Printf(“any %v is an int type”, v) case float32: fmt.Printf(“any %v is a float32 type”, v) case string: fmt.Printf(“any %v is a string type”, v) case specialString: fmt.Printf(“any %v is a special String!”, v) default: fmt.Println(“unknown type!”)

} } testFunc(whatIsThis)

}func main( ) {

TypeSwitch( )}

Construindo uma array de um tipo geral ou com variáveis de tipos diferentes

Em vimos como arrays de ints, floats e strings podem ser pesquisados e classificadas. Mas o que dizer de arrays de outros tipos, que temos que programar isso para nós mesmos? Se queremos agora sabemos que isso é possível usando a interface vazia, vamos dar-lhe o elemento apelido: type Element interface { }

Page 331: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Em seguida, deestreito um vetor struct, que contém uma slice de elemento itens:

type Vector struct {a [ ]Element

}

Vetores pode conter qualquer coisa, porque qualquer tipo implementa a interface vazia, na verdade todos os elementos podem ser de tipo diferente. Podemos definir um método At( ) que retorna o elemento om:

func (p *Vector) At(i int) Element {return p.a[i]

}

E uma função Set( ) que define o elemento:

func (p *Vector) Set(i int, Element e) {p.a[i] = e

}

Tudo no vetor é armazenado como um elemento, para obter o tipo original de volta (unboxing), precisamos usar afirmações do tipo. O compilador rejeita as alegações garantidos a falhar, mas digitar afirmações sempre executar em tempo de execução e por isso pode gerar erros de tempo de execução!

Copiar um slice de dados em uma slice de interface de { }

Suponha que você tenha uma slice de dados de myType e quer colocá-los em uma slice de interface de vazio, como em:

var dataSlice [ ] = myType FuncReturnSlice ( )var interfaceSlice [ ]} = {a interface dataSlice

Isso não funciona, o compilador lhe dá o erro: não é possível usar dataSlice (type [ ]myType) comotype [ ]interface { } in assignmentA razão é que o layout de memória de ambas as variáveis não é o mesmo.A cópia deve ser feito

explicitamente com uma declaração de alcance, como em:

var dataSlice [ ]myType = FuncReturnSlice( )var interfaceSlice [ ]interface{ } = make([ ]interface{ }, len(dataSlice))for ix, d := range dataSlice { interfaceSlice[i] = d}

estructs Nó de tipos gerais ou diferentes

No encontramos dados-estruturas como listas e árvores, usando um tipo struct recursiva chamado de nó. Os nós continha um domínio de um determinado tipo de dados. Agora, com a interface vazio à nossa disposição, os dados podem ser do mesmo tipo, e podemos escrever código genérico. Aqui está um código de partida para uma estrutura de árvore binária: a definição geral, uma newNode método para a criação de uma estrutura tão vazia, e um SetData método para dar os dados de um valor:

package mainimport “fmt”type Node struct {

le *Node

Page 332: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

data interface{ } ri *Node

}func NewNode(left, right *Node) *Node {

return &Node{left, nil, right}}func (n *Node) SetData(data interface{ }) {

n.data = data}func main( ) {

root := NewNode(nil,nil) root.SetData(“root node”)

a := NewNode(nil,nil) a.SetData(“left node”) b := NewNode(nil,nil) b.SetData(“right node”) root.le = a root.ri = b fmt.Printf(“%v\n”, root)

}

interface a interface

Um valor de interface também pode ser atribuída a um outro valor de interface, enquanto o valor de base implementa os métodos necessários. Esta conversão é verificado em tempo de execução, e quando falha ocorre um erro de tempo de execução: este é um dos aspectos dinâmicos do Go, comparável a linguagens dinâmicas como Ruby e Python. Suponha que:

var ai AbsInterface / / Declara método Abs ( )type SqrInterface interface { Sqr( ) float }var si SqrInterfacepp := new(Point) / / Dizer * Ponto implementa Abs, Sqrvar empty interface{ }

Em seguida, as seguintes declarações e afirmações do tipo são válidos:

empty = pp; / / Tudo satisfaz vazioai = empty.(AbsInterface); / / Valor subjacente pp implementa Abs ( ) / / (Insuficiência de tempo de execução de outra forma)si = ai.(SqrInterface); / / * Point tem Sqr( ) mesmo que não AbsInterfaceempty = si; / / * Ponto implementa conjunto vazio / / Nota: estaticamente verificável então digite assertion não é necessário.

Aqui está um exemplo com uma chamada de função:

type myPrintInterface interface { print( )

}func f3(x myInterface) {

x.(myPrintInterface).print( ) / / Tipo de assertion para myPrintInterface}

A conversão para myPrintInterface é totalmente dinâmico: ele vai trabalhar, desde que o tipo subjacente de x (o tipo dinâmico) define um método de impressão.

A reflexão sobre estructs

Page 333: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Algumas das possibilidades de estructs são demonstrados, Vemos que NumField( ) dá o número de campos na estrustruct, com um loop for, podemos passar por cada um deles indexado por I com Field(i).Podemos também chamar seus métodos, por exemplo, o método n onde n é o índice com:

package mainimport ( “fmt” “reflect”)type NotknownType struct { s1, s2, s3 stringfunc (n NotknownType) String( ) string { return n.s1 + “-” + n.s2 + “-” + n.s3}/ / Variável para investigar:var secret interface { } = NotknownType{“Ada”, “Go”, “Oberon”}func main( ) { value := reflect.ValueOf(secret) / / <main.NotknownType Value> typ := reflect.TypeOf(secret) / / Main.NotknownType / / Alternativa: / / Tip: = value.Type ( ) / / main.NotknownType fmt.Println(typ) knd := value.Kind( ) / / struct fmt.Println(knd) / / Percorrer os campos da struct: for i:= 0; i < value.NumField( ); i++ { fmt.Printf(“Field %d: %v\n”, i, value.Field(i)) / / Value.Field (i). SetString ("C #")}/ / Chama o primeiro método, que é String ( ):results := value.Method(0).Call(nil)fmt.Println(results) / / [Ada - Go - Oberon]}

/ * Saída:main.NotknownTypestructField 0: AdaField 1: GoField 2: Oberon[Ada - Go - Oberon]* /

Mas se tentar mudar um valor, temos um erro de execução: panic: reflect.Value.SetString using value obtained using unexported field. Assim, vemos que somente os campos exportados (começando com uma letra maiúscula) de um struct são ajustáveis, o que é demonstrado:

package mainimport (

“fmt” “reflect”

)type T struct {

A int B string

}func main( ) {

t := T{23, “skidoo”} s := reflect.ValueOf(&t).Elem( ) typeOfT := s.Type( ) for i := 0; i < s.NumField( ); i++ {

Page 334: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

f := s.Field(i) fmt.Printf(“%d: %s %s = %v\n”, i, typeOfT.Field(i).Name, f.Type( ), f.Interface( ))

} s.Field(0).SetInt(77) s.Field(1).SetString(“Sunset Strip”) fmt.Println(“t is now”, t)

}

/ * Saída:0: A int = 231: B string = skidoot is now {77 Sunset Strip}* /]

Printf e reflexão.

Os recursos do pacote de reflexão discutido na seção anterior são muito utilizadas na biblioteca padrão, por exemplo, a função printf etc usa-o para descompactar o seu … argumentos, Printf é declarado como: func Printf(format string, args ... interface{ }) (n int, err error)

O … argumento dentro Printf (ou em qualquer outro lugar) tem interface digitar { }, e Printf usa o pacote reflexão para descompactá-lo e descobrir a lista de argumentos. Como resultado, Printf conhece os tipos reais de seus argumentos. Porque eles sabem que se o argumento é assinado ou longo, não existe %u ou %ld, somente %d. Esta é também a forma de Print e Printf pode imprimir os argumentos bem sem uma seqüência de formato. Para tornar isso mais concreto, vamos implementar uma versão simplificada de tal função print-generic no exemplo a seguir, que usa uma chave do tipo de deduzir o tipo, e de acordo com esta imprime a variável fora .

package mainimport (

“os” “strconv”

)type Stringer interface {

String( ) string}type Celsius float64func (c Celsius) String( ) string {

return strconv.FormatFloat(float64(c),’f’, 1, 64) + “°C”}type Day intvar dayName = [ ]string{“Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”,“Saturday”, “Sunday”}func (day Day) String( ) string {

return dayName[day]}func print(args ...interface{ }) {

for i, arg := range args { if i > 0 {os.Stdout.WriteString(“ ”)} switch a := arg.(type) case Stringer: os.Stdout.WriteString(a.String( )) case int: os.Stdout.WriteString(strconv.Itoa(a)) case string: os.Stdout.WriteString(a) default: os.Stdout.WriteString(“???”) }

}}func main( ) {

Page 335: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

print(Day(1), “was”, Celsius(18.36))

}

tipagem dinâmica em Go

Em linguagens clássicas (como C + +, Java e C #) de dados e os métodos que agem sobre os dados estão unidos no conceito de classe: a classe contém os dois, eles não podem ser separados.

Em Go não há classes: dados (estruturas ou tipos mais gerais) e métodos são tratados ortogonalmente, eles são muito mais flexíveis.

Interfaces em Go são semelhantes aos seus homólogos Java / C #: tanto especificar um conjunto mínimo de métodos que um implementador de uma interface deve fornecer. Mas eles também são mais fluidas e genérica: qualquer tipo que fornece o código para os métodos de uma interface implicitamente implementa essa interface, sem ter que dizer explicitamente que ele faz.

Em comparação com outras línguas Go é o único que combina os valores de interface, verificação de tipo estático (não um tipo de implementar a interface?), Conversão de tempo de execução dinâmica e nenhuma exigência para declarar explicitamente que um tipo satisfaz uma interface. Essa propriedade também permite que as interfaces a ser definido e usado sem ter que modificar o código existente.

Uma função que tem um (um ou mais) parâmetro de um tipo de interface pode ser chamado com uma variável cujo tipo implementa essa interface. Tipos de implementação de uma interface pode ser passado para qualquer função que leva essa interface como um argumento.

Isto assemelha-se muito mais o duck typingin em linguagens dinâmicas como Python e Ruby, o que pode ser definido como significando que os objetos podem ser manipulados (por exemplo, passagem por funções), com base nos métodos que prestam, independentemente de seus tipos reais: o que são é menos importante do que podem ser.

Isto é ilustrado na duck_dance.go programa, onde a função DuckDance leva uma variável de tipo de interface IDuck. O programa só compila quando DuckDance for chamado em uma variável de um tipo que implementa IDuck.

package mainimport “fmt”type IDuck interface {

Quack( ) Walk( )

}func DuckDance(duck IDuck) {

for i := 1; i <= 3; i++ { duck.Quack( ) duck.Walk( )

}}type Bird struct {

/ / ...}func (b *Bird) Quack( ) {

fmt.Println(“I am quacking!”)}func (b *Bird) Walk( ) { fmt.Println(“I am walking!”)}func main( ) {

b := new(Bird) DuckDance(b)

}

Saída:

I am quacking!

Page 336: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

I am walking!I am quacking!I am walking!I am quacking!I am walking!

Se o tipo de pássaro no entanto não implementar Walk( ) (comentá-lo), então temos um erro de compilação: não pode usar b (type *Bird) como tipo IDuck no argumento da função:

* Bird não implementar IDuck (faltando método Walk)

Se chamarmos o DuckDance function ( ) para um gato, Go dá um erro do compilador, enquanto Python ou Ruby terminar em um erro de execução!

invocação de método dinâmico

No entanto, em Python, Ruby e similares pato digitação é realizada como ligação tardia (durante a execução): métodos são chamados simplesmente nesses argumentos e variáveis e resolvidas em tempo de execução (que na sua maioria têm métodos como responds_to para verificar se o objeto sabe este método, mas isso equivale a mais de codificação e teste).

Pelo contrário, em Go às necessidades de execução (na maioria das vezes) fica estaticamente verificados pelo compilador: ele verifica se um tipo implementa todas as funções de uma interface quando houver cessão de uma variável para uma variável desse interface. Se a chamada de método está em um tipo geral como interface { }, você pode verificar se a variável implementa a interface, ao fazer uma type assertion.

Como um exemplo, suponha que você tem diferentes entidades representadas como tipos que têm de ser escritos como fluxos XML. Em seguida, vamos definir uma interface para XML escrever com o método que você está procurando (tt mesmo pode ser definido como uma interface privada):

type xmlWriter interface { WriteXML(w io.Writer) error

}

Agora podemos fazer uma StreamXML função para o streaming de qualquer variável, testando com uma type assertion, se a variável passada implementa a interface, se não chamamos a sua própria função encodeToXML para fazer o trabalho:

/ / Exportados função de streaming XML.{func StreamXML(v interface{ }, w io.Writer) error {if xw, ok := v.(xmlWriter); ok { / / É uma xmlWriter, método de uso do tipo afirmou. return xw.WriteXML(w)} / / Na implementação, por isso temos de usar a nossa própria função (com talvez reflexão): return encodeToXML(v, w)}/ / Função de codificação XML interno.func encodeToXML(v interface{ }, w io.Writer) error {/ / ...}

Go usa o mesmo mecanismo em seu pacote gob: aqui eles definiram o GobEncoder duas interfaces e GobDecoder. Estes permitem que os tipos para definir uma forma própria para codificar e descodificar os dados de e para fluxos de bytes, caso contrário a maneira padrão com reflexão é usado.

Então Go oferece as vantagens de uma linguagem dinâmica, mas não as suas desvantagens de erros em tempo de execução. Isto alivia para uma parte da necessidade de testes de unidade, que é muito importante em linguagens dinâmicas, mas também apresenta uma quantidade considerável de esforço.

Go as interfaces promove separação de interesses, melhora a reutilização de código, e torna mais fácil para construir sobre os padrões que emergem como o código se desenvolve. Com interfaces Go do padrão de injeção de dependência também pode ser implementado.

Page 337: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Extracção de uma interface

Um padrão de refatoração que é muito útil é a extração de interfaces, reduzindo assim o número de tipos e métodos necessários, sem ter a necessidade de gerenciar um todo classe hierarquia como em mais Oo-linguagens baseadas em classes tradicionais.

A forma como as interfaces se comportar de Go permite que os desenvolvedores para descobrir os tipos de seus programas como escrevê-los. Se houver vários objetos que todos têm o mesmo comportamento, e um desenvolvedor deseja abstrato que o comportamento, eles podem criar uma interface e, em seguida, usar isso.

Suponha que nós achamos que precisamos de um novo TopologicalGenus interface, o que lhe dá o posto de uma forma (aqui simplesmente implementado como retornando um int). Tudo o que temos a fazer é dar os tipos que queremos essa interface para implementar o método de classificação ( ):

package mainimport “fmt”type Shaper interface {

Area( ) float32}type TopologicalGenus interface {

Rank( ) int}type Square struct {

side float32}func (sq *Square) Area( ) float32 {

return sq.side * sq.side}func (sq *Square) Rank( ) int {

return 1}type Rectangle struct {

length, width float32}func (r Rectangle) Area( ) float32 {

return r.length * r.width}func (r Rectangle) Rank( ) int {

return 2}func main( ) { r := Rectangle{5, 3} q := &Square{5} shapes := [ ]Shaper{r, q}

fmt.Println(“Looping through shapes for area ...”) for n, _ := range shapes {

fmt.Println(“Shape details: “, shapes[n]) fmt.Println(“Area of this shape is: “, shapes[n].Area( ))

} topgen := [ ]TopologicalGenus{r, q} fmt.Println(“Looping through topgen for rank ...”) for n, _ := range topgen {

fmt.Println(“Shape details: “, topgen[n]) fmt.Println(“Topological Genus of this shape is: “, topgen[n]. Rank( ))

}}

Page 338: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

/ * Saída:Looping through shapes for area ...Shape details: {5 3}Area of this shape is: 15Shape details: &{5}Area of this shape is: 25Looping through topgen for rank ...Shape details: {5 3}Topological Genus of this shape is: 2Shape details: &{5}Topological Genus of this shape is: 1* /

Então você não tem que trabalhar todas as suas interfaces de fora antes do tempo; todo o projeto pode evoluir sem invalidar decisões iniciais. Se um tipo deve implementar uma nova interface, o próprio tipo não tem que ser mudado, é necessário apenas fazer o novo método (s) do tipo.

explicitamente o que indica que um tipo implementa uma interface

Se você deseja que os tipos de uma interface explicitamente declaram que implementá-lo, você pode adicionar um método com um nome descritivo para o método set da interface. Por exemplo:

type Fooer interface { Foo( ) ImplementsFooer( )

}

Um tipo Bar deve, então, implementar o método ImplementsFooer ser um Fooer, documentar claramente o fato.

type Bar struct{ }func (b Bar) ImplementsFooer( ) { }func (b Bar) Foo( ) { }

A maioria dos códigos não fazer uso de tais restrições, já que eles limitam a utilidade da idéia de interface. Às vezes, porém, eles podem ser necessários para resolver as ambiguidades entre as interfaces semelhantes.

vazio interface e sobrecarga de funções

Em vimos que a sobrecarga de função não é permitida. Em Go isso pode ser feito por meio de um número variável de parâmetros com ... T como último parâmetro. Se tomarmos T para ser a interface vazia, e sabemos que uma variável de qualquer tipo satisfaz T, então isso nos permite passar qualquer número de parâmetros de qualquer tipo para essa função, que é o que a sobrecarga meios.

Este é aplicado na definição da função: fmt.Printf(format string, a ...interface{ }) (n int, errno error), itera esta função mais a slice de descobrir o tipo de seus argumentos de forma dinâmica. Para cada tipo parece se uma String ( ) é implementado, em caso afirmativo, isto é usado para produzir a saída.

A herança de interfaces

Quando um tipo inclui (incorporações) outro tipo (que implementa uma ou mais interfaces) como um ponteiro, em seguida, o tipo pode usar todas as interfaces de métodos.

Page 339: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Exemplo:

type Task struct { Command string *log.Logger

}

Uma factory para este tipo pode ser:

func NewTask(command string, logger *log.Logger) *Task {return &Task{command, logger}

}

Quando log.Logger implementa um método Log( ), então uma tarefa task de Task pode chamá-lo:

type ReaderWriter struct { *io.Reader *io.Writer

}

Os princípios acima são aplicadas em todos os Go-pacotes, maximing, assim, a possibilidade de utilização de polimorfismo e minimizando a quantidade de código. Este é considerado um importante as melhores práticas em Go-programação.

Interfaces de úteis podem ser detectados quando o desenvolvimento já está em andamento. É fácil adicionar novas interfaces, porque os tipos existentes não tem que mudar (eles só têm de implementar os seus métodos). Funções existentes podem, em seguida, ser generalizados de ter um parâmetro (s) de um tipo restreito a um parâmetro do tipo de interface: muitas vezes apenas a assinatura da função precisa de ser mudado. Compare-se isto com as inguagens baseadas em classes em que, nesse caso, o desenho de toda a classe de hierarquia tem de ser adaptada.

estruturas, coleções e funções de ordem superior

Muitas vezes, quando você tem um struct em seu aplicativo, você também precisa de uma coleção de (ponteiros para objetos) de que struct, como:

type Any interface{ }type Car struct {

Model string BuildYear / / ...

int}type Cars [ ]*Car

Podemos, então, usar as funções de alta ordem usando o fato de que as funções podem ser argumentos na definição da funcionalidade necessária, como por exemplo:

1) na definição de um processo geral ( ) função, que se assume uma função f que opera em todos os carros:

/ / Processar todos os cars com a função dada f:func (cs Cars) Process(f func(car *Car)) {

for _, c := range cs {f(c)

}}

Page 340: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

2) construir sobre isso, certifique-Encontrar-funções para obter subconjuntos, e Processo chamando ( ) com um fecho (para que ele saiba os carros slice locais):

/ / Encontrar todos os carros que correspondam a um determinado critério.func (cs Cars) FindAll(f func(car *Car) bool) Cars {

cars := make([ ]*Car, 0) cs.Process(func(c *Car) {

if f(c) {append(cars,c)

} ) return cars

}

3) e fazer uma funcionalidade Mapa, produzindo algo de cada objeto car:

Carros / / processo e criar novos dados.func (cs Cars) Map(f func(car *Car) Any) [ ]Any {

result := make([ ]Any, 0) ix := 0 cs.Process(func(c *Car) {

result[ix] = f(c) ix++

}) return result

}

Agora podemos definir consultas concretas como:

allNewBMWs: = allCars.FindAll (func (car *Car) bool {return (car.Manufacturer == “BMW”) && (car.BuildYear > 2010)})

Nós também pode retornar funções com base em argumentos. Talvez a gente gostaria de acrescentar carros para coleções baseadas nos fabricantes, mas esses podem ser variados.Assim, definimos uma função para criar uma função especial de acrescentar, bem como um mapa de coleções:

4) func MakeSortedAppender (fabricantes [ ] string) (func (car * Car), map [string] Cars){/ / Prepare mapas de carros ordenados.

sortedCars := make(map[string]Cars) for _, m := range manufacturers {

sortedCars[m] = make([ ]*Car, 0)}sortedCars ["default"] = fazer ([ ] * Carro, 0)/ / Prepare appender função:

appender := func(c *Car) {if _, ok := sortedCars[c.Manufacturer]; ok {

sortedCars[c.Manufacturer] = append(sortedCars[c. Manufacturer], c)

} else {sortedCars[“Default”] = append(sortedCars[“Default”], c)

} } return appender, sortedCars

}

Nós agora podemos usá-lo para resolver os nossos carros em coleções individuais, como em:

Page 341: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

manufacturers := [ ]string{“Ford”, “Aston Martin”, “Land Rover”, “BMW”, “Jaguar”}sortedAppender, sortedCars := MakeSortedAppender(manufacturers)allUnsortedCars.Process(sortedAppender)BMWCount := len(sortedCars[“BMW”])

Fazemos este trabalho código na seguinte cars.go programa (aqui nós mostramos apenas o código em main ( ), o resto do código já foi mostrado acima:

/ / .. tipos e funçõesfunc main( ) { / / Fazer alguns carros:

ford := &Car{“Fiesta”,“Ford”, 2008} bmw := &Car{“XL 450”, “BMW”, 2011} merc := &Car{“D600”, “Mercedes”, 2009} bmw2 := &Car{“X 800”, “BMW”, 2008} / / query: allCars := Cars([ ]*Car{ford, bmw, merc, bmw2}) allNewBMWs := allCars.FindAll(func(car *Car) bool {

return (car.Manufacturer == “BMW”) && (car.BuildYear > 2010) }) fmt.Println(“AllCars: “, allCars) fmt.Println(“New BMWs: “, allNewBMWs) / / manufacturers := [ ]string{“Ford”, “Aston Martin”, “Land Rover”, “BMW”, Jaguar”} sortedAppender, sortedCars := MakeSortedAppender(manufacturers) allCars.Process(sortedAppender) fmt.Println(“Map sortedCars: “, sortedCars) BMWCount := len(sortedCars[“BMW”]) fmt.Println(“We have “, BMWCount, “BMWs”)

}

que produz o seguinte resultado:

AllCars: [0xf8400038a0 0xf840003bd0 0xf840003ba0 0xf840003b70]Novos BMWs: [0xf840003bd0]Mapa sortedCars: mapa [padrão: [0xf840003ba0] Jaguar: [ ] Land Rover: [ ] BMW: [0xf840003bd00xf840003b70] Aston Martin: [ ] Ford: [0xf8400038a0] ]Temos 2 BMWs

Além da FMT pacotes e os, também vamos precisar importar e usar o bufio pacote para entrada e saída de buffer.

Lendo entrada do usuário

Como podemos ler entrada do usuário a partir do teclado (console)? A entrada é lido a partir do teclado ou a entrada padrão, que é os.Stdin. A forma mais simples é utilizar o Sscan-família de digitalização e de funções do fmt pacote, como ilustrado neste programa:

/ / Lê a entrada do console:package mainimport “fmt”var (

firstName, lastName, s string i int f float32 input = “56.12 / 5212 / Go” format = “%f / %d / %s”

Page 342: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

)func main( ) {

fmt.Println(“Please enter your full name: “) fmt.Scanln(&firstName, &lastName) / / fmt.Scanf(“%s %s”, &firstName, &lastName) fmt.Printf(“Hi %s %s!\n”, firstName, lastName) / / Hi Chris Naegels fmt.Sscanf(input, format, &f, &i, &s) fmt.Println(“From the string we read: “, f, i, s)

/ / ouwtput: From the string we read: 56.12 5212 Go}

Procura no texto Scanln ler da entrada padrão, armazenando valores separados por espaços sucessivos em argumentos sucessivos, que interrompe a digitalização em uma nova linha.Scanf faz o mesmo, mas é usa o seu primeiro parâmetro como formato de cadeia para ler os valores das variáveis. Sscan e amigos funcionam da mesma maneira, mas ler a partir de uma cadeia de entrada como ao invés da entrada padrão. Você pode verificar o número de itens lidos e se o erro quando algo dá errado.

Mas também pode ser feita com um leitor tamponada do bufio pacote, como é demonstrado no seguinte programa:

package mainimport (

“fmt” “bufio” “os”

)var inputReader *bufio.Reader

var input string var err error

func main( ) { inputReader = bufio.NewReader(os.Stdin) fmt.Println(“Please enter some input: “) input, err = inputReader.ReadString(‘\n’) if err == nil {

fmt.Printf(“The input was: %s\n”, input) }}

inputReader na linha: é um ponteiro para um leitor em bufio. Este leitor é criado e vinculado a inputReader padrão de entrada: = inputReader := bufio.NewReader(os.Stdin).

O construtor bufio.NewReader ( ) tem a assinatura: func NewReader(rd io.Reader) *ReaderEle toma como argumento qualquer objeto que satisfaz a interface io.Reader (qualquer objeto que tem

uma leitura adequada e retorna um novo io.Reader tampão que lê a partir do leitor de dado, satisfaz este requisito os.Stdin .

O leitor tem um método ReadString(delim byte), em que lê a entrada até ser encontrado, delim será incluído, lido é colocado em um buffer.

ReadString retorna a seqüência de leitura zero para o erro, quando ele lê até o estreitol de um arquivo, a leitura string é retornada e io.EOF; se delim não for encontrado: error err != nil is returned.

No nosso caso, a entrada do teclado é lido até que a tecla ENTER (que contém '\ n') é aproveitado.Os.Stdout da saída padrão é a tela; os.Stderr é onde erro de informação pode ser escrito, em sua

maioria igual a os.Stdout.Em código Go normal as declarações var são omitidos e as variáveis são declaradas com :=, como:

inputReader := bufio.NewReader(os.Stdin)input, err := inputReader.ReadString(‘\n’)

Vamos aplicar esta linguagem a partir de agora.

O segundo exemplo lê a entrada do teclado com alguns switch-versões diferentes:

Page 343: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport (

“fmt” “os” “bufio”

)func main( ) {

inputReader := bufio.NewReader(os.Stdin) fmt.Println(“Please enter your name:”) input, err := inputReader.ReadString(‘\n’) if err != nil {

fmt.Println(“There were errors reading, exiting program.”) return

} fmt.Printf(“Your name is %s”, input)

/ / Para Unix: teste com delimitador "\ n", para Windows: teste com "\ r \ n" switch input {

case “Philip\r\n”: fmt.Println(“Welcome Philip!”) case “Chris\r\n”: fmt.Println(“Welcome Chris!”) case “Ivo\r\n”: fmt.Println(“Welcome Ivo!”) default: fmt.Printf(“You are not welcome here! Goodbye!”) }

/ / Versão 2: switch input { case “Philip\r\n”: fallthrough case “Ivo\r\n”: fallthrough case “Chris\r\n”: fmt.Printf(“Welcome %s\n”, input) default: fmt.Printf(“You are not welcome here! Goodbye!\n”) }

/ / Versão 3: switch input { case “Philip\r\n”, “Ivo\r\n”: fmt.Printf(“Welcome %s\n”, input) default: fmt.Printf(“You are not welcome here! Goodbye!\n”) }

}

Observe como as quebras de linha para Unix e Windows são diferentes!

Leitura de um arquivo

Arquivos em Go são representados por ponteiros para objetos do tipo os.File, também chamado filehandles. O os.Stdin entrada padrão e saída os.Stdout usamos na seção anterior são ambos do tipo *os.

package mainimport (

“bufio”“fmt”

i o“ “os”}func main( ) {

inputFile, inputError := os.Open(“input.dat”)if inputError != nil { fmt.Printf(“An error occurred on opening the inputfile\n” +

“Does the file exist?\n” +“Have you got acces to it?\n”) return / / exit the function on error

Page 344: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

} defer inputFile.Close( )

inputReader := bufio.NewReader(inputFile) for { inputString, readerError := inputReader.ReadString(‘\n’) if readerError == io.EOF { return } fmt.Printf(“The input was: %s”, inputString) }

}

O inputFile variável é do tipo *os.File: esta é uma estruct que representa um descritor de arquivo aberto (um identificador de arquivo). Em seguida, o arquivo precisa ser aberto com a função Open para os: este aceita um nome de arquivo de parâmetro do tipo string, aqui input.dat, e abre o arquivo no modo somente leitura.

Esta lata de resultado claro em um erro quando o arquivo não existe ou o programa não tem direitos suficientes para abrir o arquivo: inputfile, inputError = os.Open ("input.dat"). Se tivermos um arquivo, garantimos com defer.Close ( ) que o arquivo é fechado no estreitol, e então aplicar bufio.NewReader para obter uma variável leitor.

Usando o leitor de bufio (e o mesmo vale para o escritor) como fizemos aqui, significa que podemos trabalhar com convenientes objetos string de alto nível, completamente isolado do bytes brutos que representam o texto no disco.

Em seguida, lemos cada linha do arquivo (delimitado por '\ n'), em um infinito loop for com o método ReadString ('\ n') ou ReadBytes ('\ n').

Observação:

Em um exemplo anterior, vimos-arquivos de texto em Unix estreitol em \n, mas no Windows é \r\n. Ao utilizar o método ReadString ou ReadBytes com \n como um delimitador que você não tem que se preocupar com this.The uso do ReadLine ( ) método também poderia ser uma boa alternativa.

Quando li o arquivo após o estreitol então readerError != Nil o loop for é deixada através da instrução de retorno.

(Na verdade io.EOF é verdade), e Algumas alternativas:

1) Ler o conteúdo de um arquivo inteiro em uma string: Se isso é suficiente para que você precisa, você pode usar o método ioutil.ReadFile ( ) do pacote io/ioutil, que retorna um byte [ ] contendo os bytes lidos e nulo ou um possível erro. Analogamente a função WriteFile ( ) escreve um byte [ ] em um arquivo.

package mainimport (

“fmt” “io/ioutil” “os”

)func main( ) {

inputFile := “products.txt” outputFile := “products_copy.txt” buf, err := ioutil.ReadFile(inputFile) if err != nil { fmt.Fprintf(os.Stderr, “File Error: %s\n”, err)

/ / panic(err.Error( )) } fmt.Printf(“%s\n”, string(buf)) err = ioutil.WriteFile(outputFile, buf, 0x644) if err != nil {

panic(err. Error( ))

Page 345: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}}

2) Buffered Read: Em vez de usar ReadString( ), no caso mais geral de um arquivo não dividido em linhas ou um arquivo binário, poderíamos ter usado o método Read( ) no bufio.Reader, com o parâmetro de entrada a:

buf := make([ ]byte, 1024) ...n, err := inputReader.Read(buf)if (n == 0) { break}

3) Leitura colunas de dados de um arquivo: Se as colunas de dados são separadas por um espaço, você pode usar a série FScan função do pacote "fmt". Isto é aplicado o seguinte programa, que lê dados a partir de 3 colunas para as variáveis v1, v2 e v3, pois eles são, então, anexada ao slices coluna.

package mainimport (

“fmt” “os”

)func main( ) {

file, err := os.Open(“products2.txt”) if err != nil {

panic(err) } defer file.Close( ) var col1, col2, col3 [ ]string for {

var v1, v2, v3 string _, err := fmt.Fscanln(file, &v1, &v2, &v3)

/ / scans until newline if err != nil {

break } col1 = append(col1, v1) col2 = append(col2, v2) col3 = append(col3, v3)

} fmt.Println(col1) fmt.Println(col2) fmt.Println(col3)

}

/ * Saída:[ABC FUNC GO][40 56 45][150 280 356]* /

Observação:

O caminho de arquivo subpackage do caminho do pacote fornece funções para a manipulação de nomes de arquivos e caminhos que funcionam em plataformas de sistema operacional, como por exemplo a base de dados de function ( ) retorna o último elemento de um caminho sem arrastando separador: import “path/filepath”

filename := filepath.Base(path)

pacote compactado: a leitura de um arquivo zipado

Page 346: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

A compressa pacote da biblioteca padrão oferece facilidades para a leitura de arquivos compactados nos seguintes formatos: bzip2, flate, gzip, LZW e zlib.

O programa a seguir ilustra a leitura de um ficheiro de gzip:

package mainimport (

“fmt” “bufio” “os” “compress/gzip”

)func main( ) {

fName := “MyFile.gz” var r *bufio.Reader fi, err := os.Open(fName) if err != nil { fmt.Fprintf(os.Stderr, “%v, Can’t open %s: error: %s\n”, os.Args[0], fName, err) os.Exit(1) } fz, err := gzip.NewReader(fi) if err != nil {

r = bufio.NewReader(fi) } else {

r = bufio.NewReader(fz) } for {

line, err := r.ReadString(‘\n’) if err != nil { fmt.Println(“Done reading file”) os.Exit(0)

} fmt.Println(line)

}}

Escrevendo em um arquivo

Isto é demonstrado no seguinte programa:

package mainimport (

“os” “bufio” “fmt”

)func main ( ) {

outputFile, outputError := os.OpenFile(“output.dat”, os.O_WRONLY|os.O_CREATE, 0777) if outputError != nil {

fmt.Printf(“An error occurred with file creation\n”) return

} defer outputFile.Close( ) outputWriter:= bufio.NewWriter(outputFile) outputString := “hello world!\n” for i:=0; i<10; i++ {

Page 347: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

outputWriter.WriteString(outputString) } outputWriter.Flush( )

}

Além de um identificador de arquivo, precisamos agora de um bufio Writerfrom. Abrimos um output.dat arquivo para write-only; o arquivo é criado quando ele não existe com:

outputFile, outputError := os.OpenFile(“output.dat”, os.O_WRONLY|os.O_CREATE, 0777)Vemos que a função OpenFile leva um nome de arquivo, um ou mais flags (logicamente OR-D em

conjunto, utilizando o | OR bit a bit operador, se mais de um), e as permissões de arquivo para usar.

Os seguintes sinalizadores são comumente usados:

os.O_RDONLY: a flag de leitura para acesso somente leituraos.WRONLY: A flag de gravação para acesso somente para gravaçãoos.O_CREATE: a criação da flag: criar o arquivo se ele não existiros.O_TRUNC: a flag truncate: truncar o tamanho 0 se o arquivo já existe

Ao ler, as permissões de arquivo são ignoradas para que possamos utilizar um valor de 0. Ao escrever usamos o padrão de permissões de arquivos Unix de 0777.

Então nós fazemos o objeto escritor (buffer) com: outputWriter.WriteString(outputString)O loop for repete 10 vezes por gravação para o buffer: outputWriter.WriteString(outputString)é então escrito completamente para o arquivo com: outputWriter.Flush ( )Nas tarefas de escrita simples, isto pode ser feito mais eficiente com: fmt.Fprintf(outputFile, “Sometest data.\n”) usando a versão F das funções fmt impressão que pode escrever a qualquer io.Writer,

incluindo um arquivo.

O programa filewrite.go ilustra uma alternativa para fmt.FPrintf:

package mainimport “os”func main( ) {

os.Stdout.WriteString(“hello, world\n”) f, _ := os.OpenFile(“test”, os.O_CREATE|os.O_WRONLY, 0) defer f.Close( ) f.WriteString(“hello, world in a file\n”)

}

Com os.Stdout.WriteString (“hello, world\n”) também podemos escrever para a tela.

Em f, _ := os.OpenFile ("teste", os.O_CREATE | os.O_WRONLY,0) que crie ou abra para escrever-somente um arquivo "teste". Um erro possível é desconsiderada com _.

Não fazer uso de um buffer e escrever imediatamente para o arquivo com: f.WriteString( )

Copiando arquivos

Como você copiar um arquivo para outro arquivo? A maneira mais simples é usar cópia do pacote io:

package mainimport (

“fmt” “io” “os”

)func main( ) {

Page 348: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

CopyFile(“target.txt”, “source.txt”) fmt.Println(“Copy done!”)

}func CopyFile(dstName, srcName string) (written int64, err error) {

src, err := os.Open(srcName) if err != nil {

return } defer src.Close( ) dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) if err != nil {

return } defer dst.Close( ) return io.Copy(dst, src)

}

Observe o uso de defer: quando a abertura do arquivo de destino produziria um erro e voltar, então ainda a defer e assim src.Close ( ) é executado. Se isto não seria feito, o arquivo de origem permaneceria aberta, usando recursos.

arquivos de leitura com um buffer

Nós combinamos as técnicas de leitura em buffer de um arquivo e de linha de comando flag (flag) análise no exemplo a seguir. Se não há argumentos que é digitado em é mostrado novamente na saída.

Os argumentos são tratados como nomes de arquivos e quando os arquivos existem, o seu conteúdo é mostrado:

package mainimport (

“io” “os” “fmt” “bufio” “flag”

)func cat(r *bufio.Reader) {

for { buf, err := r.ReadBytes(‘\n’) if err == io.EOF {

break } fmt.Fprintf(os.Stdout, “%s”, buf)

} return

}func main( ) {

flag.Parse( ) if flag.NArg( ) == 0 {

cat(bufio.NewReader(os.Stdin)) } for i := 0; i < flag.NArg( ); i++ {

f, err := os.Open(flag.Arg(i)) if err != nil {

fmt.Fprintf(os.Stderr, “%s:error reading from %s: %s\n”, os.Args[0], flag.Arg(i), err.Error( )) continue

Page 349: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

} cat(bufio.NewReader(f))

}}

Ler e escrever arquivos com slices

Slices fornecer a maneira padrão Go para lidar com I / O buffers, eles são usados na seguinte segunda versão do gato função, que lê um arquivo em um infinito loop for (até EOF fim-de-arquivo) em um buffer em slices, e escreve para a saída padrão.

func cat(f *os.File) { const NBUF = 512 var buf [NBUF]byte for { switch nr, err := f.Read(buf[:]); true {

case nr < 0: fmt.Fprintf(os.Stderr, “cat: error reading: %s\n”, err.Error( )) os.Exit(1) case nr == 0: / / EOF return case nr > 0: if nw, ew := os.Stdout.Write(buf[0:nr]); nw != nr { fmt.Fprintf(os.Stderr, “cat: error writing: %s\n”,

ew.String( )) } } }}

Este código é obtido abaixo que utiliza os.file e seu método de leitura do pacote de ósmio:

package mainimport ( “flag” “fmt” “os”)func cat(f *os.File) { const NBUF = 512 var buf [NBUF]byte for { switch nr, err := f.Read(buf[:]); true { case nr < 0:

fmt.Fprintf(os.Stderr, “cat: error reading: %s\n”, err.Error( )) os.Exit(1)

case nr == 0: / / EOF return

case nr > 0: if nw, ew := os.Stdout.Write(buf[0:nr]); nw != nr {

fmt.Fprintf(os.Stderr, “cat: error writing: %s\n”, ew.String( ))

} } }}

Page 350: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func main( ) { flag.Parse( ) / / Scans the arg list and sets up flags if flag.NArg( ) == 0 { cat(os.Stdin) } for i := 0; i < flag.NArg( ); i++ { f, err := os.Open(flag.Arg(i)) if f == nil {

fmt.Fprintf(os.Stderr, “cat: can’t open %s: %s\n”, flag.Arg(i), err)

os.Exit(1) } cat(f) f.Close( ) }}

Usando defer para fechar um arquivo

A palavra-chave é muito útil para garantir que o arquivo aberto também será fechado no estreitol da função, como no seguinte trecho:

func data(name string) string { f := os.Open(name, os.O_RDONLY, 0) defer f.Close( ) / / idiomatic Go code! contents := io.ReadAll(f) return contents}

Um exemplo prático da utilização de interfaces: fmt.Fprintf

Esse programa é uma boa ilustração do conceito de interfaces em io.

package mainimport (

“bufio”“fmt”“os”

)func main( ) {

/ / unbuffered: os.Stdout implements io.Writer fmt.Fprintf(os.Stdout, “%s\n”, “hello world! - unbuffered”) / / buffered: buf := bufio.NewWriter(os.Stdout) / / and now so does buf: fmt.Fprintf(buf, “%s\n”, “hello world! - buffered”) buf.Flush( )

}

Saída:hello world! - unbufferedhello world! - buffered

Aqui é a assinatura real de fmt.Fprintf ( ):func Fprintf(w io.Writer, format string, a ...) (n int, err error)

Page 351: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Ele não escreve para um arquivo, ele escreve para uma variável do tipo io.Writer, isto é: Writer definida no pacote io: type Writer interface {

Write(p [ ]byte) (n int, err error) }

fmt.Fprint( ) escreve uma string de acordo com uma seqüência de formato para seu primeiro argumento, que deve implementar io.Writer. Fprintf( ) pode escrever a qualquer tipo que tem um método de gravação, incluindo os.Stdout, os arquivos (como os.File), tubos, conexões de rede, canais, etc .., e também para escrever buffers de pacote bufio. Este pacote define um tipo escritor struct {…}

bufio.Writer implementa o método de gravação: func (b *Writer) Write(p [ ]byte) (nn int, err error)

Ele também tem uma fábrica: dar-lhe um io.Writer, ele retornará um io.Writer tampão na forma de um bufio.

Escritor:func NewWriter (wr io.Writer) (b * Writer)Buffer funciona para qualquer coisa que escreve.Nunca se esqueça de usar Flush ( ) quando terminar a escrita em buffer, então o último ouput (saida)

não será escrito.

erro de manipulação e Testes

GO não tem um mecanismo de exception, como o try/catch em Java ou NET, por exemplo:. Você não pode lançarexception. Em vez disso, tem um mecanismo de defer-panic-and-recover.

Os designers de Go pensaram que o mecanismo de try/catch é excessivamente utilizado e que o lançamento de exceções ( exception) em camadas inferiores para as camadas mais elevadas de código, poi, usa muitos recursos. O mecanismo que inventado para Go um pode "pegar" exceção (exception) , mas é muito mais leve, e mesmo assim só deve ser utilizado como último recurso.

A maneira de lidar com erros Go é para funções e métodos para retornar um objeto de erro como sua única ou o último de valor ou resultado nulo se ocorreu e nenhum erro para chamar funções de verificar sempre o erro que eles recebem. Nunca ignore os erros, porque ignorá-los pode levar a falhas do programa. Lidar com os erros e voltar a partir da função em que ocorreu o erro com uma mensagem de erro para o usuário: dessa forma, se algo der errado, o programa Irá continuar a funcionar e o usuário será notificado. O objetivo do panic e recover é lidar com (inesperados) problemas genuinamente excepcionais e não com erros normais.

Rotinas de biblioteca deve muitas vezes retornar algum tipo de indicação de erro para a função de chamada. A maneira idiomática de Go para detectar e relatar erro-condições:

- Uma função que pode resultar em um erro retorna duas variáveis, um valor e um código de erro; este último é nulo, em caso de sucesso, e != nil, no caso de uma condição de erro.

- Após a chamada de função que o erro seja verificado, no caso de um erro (se o erro != nil) A execução da função real (ou se necessário, o programa inteiro) estará parado.

No seguinte código de pacote pack1 é testado em seu código de retorno:

if value, err := pack1.Func1(param1); err != nil {fmt.Printf(“Error %s in pack1.Func1 with parameter %v”, err.Error( ), param1)return / / Ou: retorno err}/ / Processo (valor)

Sempre um erro atribuir a uma variável dentro de um composto instrução if, tornando o código mais claro. Em vez de fmt.Printf correspondente métodos do pacote de registro poderiam ser usado, ou mesmo panic, se não se importa que o programa pare.

13.1 Erro de manipulaçãoGo tem um tipo de interface de erro pré-definido:Interface tipo de erro {Erro ( ) string}

Page 352: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

valores de erros são usados para indicar um estado anormal, mais tarde vamos ver como usá-lo em operações. Os erros de pacote contém um errorString struct que implementa a interface de erro. Para parar a execução de um programa em um estado de erro, podemos usar erro os.Exit (1).

Definindo erros

Sempre que você precisa de um novo tipo de erro, fazer com o errors.New função do pacote de erros (que você terá que importar), e dar-lhe um erro-string apropriado, como segue:

err := errors.New(“math - square root of negative number”)

package mainimport (

“errors” “fmt”

) fmt.Printf(“error: %v”, errNotFound)}/ / error: Not found error

Aplicado numa função de teste ao parâmetro de uma função a square root, isto pode ser usado como:

func Sqrt(f float64) (float64, error) {if f < 0 {

return 0, errors.New (“math - square root of negative number”) } / / Implementação de Sqrt

}

Você poderia chamar esta função da seguinte forma:

if f, err := Sqrt(-1); err != nil {fmt.Printf(“Error: %s\n”, err)

}

e porque fmt.Printf automaticamente usa seu método String( ), o error-string “Error:math - square root of negative number” é impresso. Porque há muitas vezes nós usamos um prefixo como erro: aqui, não comece sua seqüência de erro com uma letra maiúscula.

Na maioria dos casos, é interessante fazer um tipo struct de erro personalizada, que para além do (nível baixo) erro de mensagem também contém outras informações úteis, tais como a operação que estava ocorrendo (arquivo aberto, ...), o pleno método do caminho-nome ou url que estava envolvido, etc A String( ), em seguida, fornece uma concatenação informativo de todas essas informações. Como exemplo, veja PathError que pode ser emitido a partir de uma os.Open:

/ / PathError registra um erro e o caminho operação e o arquivo que causou.

type PathError struct { / / "Aberto", "unlink", etcPath string / / O arquivo associado.Err error / / Retornado pela chamada do sistema.}func (e *PathError) String ( ) string { return e.Op + “ ” + e.Path + “: “+ e.Err.Error( )}

No caso de diferentes-condições de erro possíveis podem ocorrer, pode ser útil para testar com uma assertion (assertion) de tipo ou tipo de chave para o erro exato e, possivelmente, tentar um remédio ou uma

Page 353: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

recuperação do erro de situação:/ /err != nilif e, ok := err.(*os.PathError); ok { / / Situação remédio}

Ou:

switch err := err.(type) {case ParseError:

PrintParseError(err)case PathError:

PrintPathError(err)...default:

fmt.Printf(“Not a special error, just %s\n”, err)}

Como um segundo exemplo, considere o pacote json. Isto especifica um tipo SyntaxError que a função json.Decode retorna quando ele encontra um erro de sintaxe analisar um documento JSON:

type SyntaxError struct { msg string / / descrição do erro/ / error occurred after reading Offset bytes, from which line and columnnr can be obtained Offset int64}

func (e *SyntaxError) String( ) string { return e.msg }

No código de chamada que você poderia voltar a testar se o erro é desse tipo com uma assertion tipo, como este:

if serr, ok := err.(*json.SyntaxError); ok { line, col := findLine(f, serr.Offset) return fmt.Errorf(“%s:%d:%d: %v”, f.Name( ), line, col, err)

}

Um pacote também pode definir o seu próprio erro específico com métodos adicionais, como net.Error:

package nettype Error interface { Timeout( ) bool / / É o erro de um tempo limite? Temporary( ) bool / / é o erro temporário?}

Como você viu, em todos os exemplos a seguinte convenção de nomenclatura foi aplicado: tipos de erro terminam em "Error" e as variáveis de erro são chamados (ou começar) “err” ou "Err".

syscall é o de baixo nível, pacote externo, o que fornece uma interface primitiva para chamadas do sistema operacional subjacente, estes inteiros retornam códigos de erro, o tipo syscall.Errno implementa a interface de erro.

r, err := syscall.Open(name, mode, perm)if err != 0 {

fmt.Println(err.Error( ))}

os também fornece um conjunto padrão de erro-variáveis como os.EINVAL, que vêm de syscall - Erros:

Page 354: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

var ( EPERM Error = Errno(syscall.EPERM) ENOENT Error = Errno(syscall.ENOENT) ESRCH Error = Errno(syscall.ESRCH) EINTR Error = Errno(syscall.EINTR) EIO Error = Errno(syscall.EIO) ...

)

Fazendo um objeto erro com fmt

Muitas vezes você vai querer voltar uma string mais informativo com o valor do parâmetro errado inserido por exemplo: isso é feito com a função fmt.Errorf ( ): ele funciona exatamente como fmt.Printf ( ), tendo uma seqüência de formato com um minério mais especificadores de formato e um número correspondente de variáveis a serem substituídos. Mas em vez de imprimir a mensagem que gera um objeto de erro com essa mensagem.

Aplicado à nossa Sqrt-exemplo de cima:

if f < 0 {retornar 0, fmt.Errorf(“math: square root of negative number %g”, f)}

2 º exemplo: durante a leitura a partir da linha de comando que gera um erro com uma mensagem de uso quando uma flag ajuda é dada:

if len(os.Args) > 1 && (os.Args[1] == “-h” || os.Args[1] == “--help”) {err = fmt.Errorf(“usage: %s infile.txt outfile.txt”, filepath.Base(os.

Args[0]))return

}

exceções em tempo de execução e de panic

Quando os erros de execução ocorrer, tais como a tentativa de índice de uma array fora dos limites ou uma assertion tipo de falha, o tempo de execução Go provoca panic em tempo de execução com um valor do tipo de interface runtime.Error, eo programa trava com uma mensagem do erro, o valor tem um RuntimeError ( ) método, para distingui-lo de um erro normal.

Mas um panic também podem ser iniciadas a partir do código diretamente: quando a condição de erro (que estamos testando no código) é tão grave e Irrecuperável que o programa não pode continuar, a função de panic é usada, o que efetivamente cria um erro de tempo de execução que vai parar o programa. É preciso um argumento de qualquer tipo, geralmente uma string, para ser impresso quando o programa morre. O tempo de execução Go tem o cuidado de parar o programa e emitir algumas informações de depuração. Como funciona é ilustrado na Listagem

package mainimport “fmt”func main( ) {

fmt.Println(“Starting the program”) panic(“A severe error occurred: stopping the program!”) fmt.Println(“Ending the program”)

}

E a saída é:

Page 355: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Starting the programpanic: A severe error occurred: stopping the program!panic PC=0x4f3038runtime.panic+0x99 /go/src/pkg/runtime/proc.c:1032

runtime.panic(0x442938, 0x4f08e8)main.main+0xa5 E:/Go/GoBoek/code examples/chapter 13/panic.go:8

main.main( )runtime.mainstart+0xf 386/asm.s:84

runtime.mainstart( )runtime.goexit /go/src/pkg/runtime/proc.c:148

runtime.goexit( )

Um exemplo concreto, verificando se o programa inicia-se com um usuário conhecido:

var user = os.Getenv(“USER”)func check( ) {

if user == “” {panic(“Unknown user: no value for $USER”)

}}

Isto pode ser verificado em uma função init( ) de um pacote que está importando.Panic também pode ser usado no padrão de tratamento de erros, quando o erro tem de parar o

programa:

if err != nil {panic(“ERROR occurred:” + err.Error( ))

}

Go em panic:

Se o panic é chamado a partir de uma função aninhada, ele imediatamente interrompe a execução da função atual, tudo defer declarações são garantidos para executar e, em seguida, o controle é dado ao autor da chamada a função, que recebe esta chamada a entrar em panic. Este boia até o nível superior, a execução adia, e no topo da pilha o programa trava e a condição de erro é relatado na linha de comando usando o valor dado a entrar em panic: essa sequência de terminação é chamado panicking.

A biblioteca padrão contém uma série de funções, cujo nome é prefixado com obrigação, como regexp.MustCompile ou template.Must; estas funções de panic( ) ao converter a string que em uma expressão regular ou modelo produz um erro.

Claro derrubar um programa com o panic não deve ser deixado no anônimato, por isso todos os esforços devem ser exercidos para remediar a situação e deixar que o programa continue.

Recover

Como o nome indica esta função built-in pode ser usado para recuperar de um panic ou uma condição de erro, que permite que um programa para recupere o controle de um goroutine em panic, parar a sequência de terminação e, portanto, de continuar a execução normal.

recover só é útil quando chamado dentro de uma função diferido: Em seguida, recupera o valor de erro, passou pela chamada de panic, quando usado em execução normal de uma chamada para recuperar retornará nulo e não têm outro efeito.

Resumido: panic faz com que a pilha relaxe até que um adiada recover( ) é encontrado ou o programa termina.

A função de proteção no exemplo abaixo invoca o argumento da função g e protege chamadas de panics de tempo de execução levantadas por g, mostrando a mensagem x do panic:

Page 356: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func protect(g func( )) {defer func( ) {

log.Println(“done”) / / Println executa normalmente, mesmo se houver um panic if err := recover( ); err != nil { log.Printf(“run time panic: %v”, err) } } ( ) log.Println(“start”)g ( ) / /possível de tempo de execução de erros}

É análogo ao bloco catch no Java e. NET.

Log implementa um pacote de registro simples: a logger padrão escreve para o erro padrão e imprime a data e hora de cada mensagem registrada. Além das funções println e Printf, as funções slices Exit(1) para depois de escrever a mensagem de log, as funções de saída de forma idêntica. As funções de panic chamam panic depois de escrever a mensagem de log, use isso quando uma condição crítica ocorre eo programa deve ser interrompido, como no caso em que um servidor web não poderia ser iniciado.

O pacote de log também define um tipo de interface Logger com os mesmos métodos, quando você quiser definir um sistema de registro personalizado.

Aqui está um exemplo completo que ilustra como panic(panic), e recover (recuperar) o trabalho em conjunto:

package mainimport (

“fmt”)func badCall( ) {

panic(“bad end”)}func test( ) { defer func( ) { if e := recover( ); e != nil { fmt.Printf(“Panicking %s\r\n”, e); } }( ) badCall( ) fmt.Printf(“After bad call\r\n”);}func main( ) { fmt.Printf(“Calling test\r\n”); test( ) fmt.Printf(“Test completed\r\n”);}/ * Saída:Calling testPanicking bad endTest completed* /Defer, panic e recover formam em um sentido também um mecanismo de controle de fluxo, como if,

for, etcEsse mecanismo é usado em vários lugares na biblioteca padrão Go, por exemplo, no pacote json ao

decodificar ou no pacote regexp na função Compile. A convenção nas bibliotecas Go é que, mesmo quando um pacote usa panic internamente, a recuperar é feito para que a sua API externa ainda apresenta valores de retorno de erro explícitas.

erro de manipulação e em panic em um pacote personalizado

Page 357: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Esta é uma prática que cada escritor de pacotes personalizados devem ser aplicadas:1) sempre recuperar de panic no pacote: sem o explícito panic( ) devem ser autorizados a cruzar um

limite de pacote2) retornar erros como valores de erro para os chamadores do seu pacote.Dentro de um pacote, no entanto, especialmente se houver profundamente chamadas aninhadas para

funções não-exportados, pode ser útil (e melhorar a legibilidade) para usar o panic para indicar condições de erro que devem ser traduzidos em um erro para a função de chamada.

Isto é muito bem ilustrado no código a seguir. Temos um pacote de análise simples que analisa cadeias de entrada de slices de inteiros, mas também contém o seu ParseError especializado.

Este panic pacote (em fields2numbers função) quando não há nada para converter ou quando a conversão para número inteiro falhar. No entanto, a função Parse exportado pode recuperar desta e retorna um erro com todas as informações para o seu chamador. Para mostrar como funciona o pacote é chamado de panic_recover.

package parseimport (

“fmt” “strings” “strconv”

)/ / A ParseError indica um erro na conversão de uma palavra em um número inteiro.type ParseError struct { Index int / / O índice para a lista separada por espaços de palavras. Word string / / A palavra que gerou o erro de análise. / / um erro em bruto que precipitou a este erro. Error err}/ / String retorna uma mensagem de erro legível.func (e *ParseError) String( ) string { return fmt.Sprintf(“pkg parse: error parsing %q as int”, e.Word)}/ / Parse analisa as palavras separadas por espaço em em colocar como inteiros.func Parse(input string) (numbers [ ]int, err error) {

defer func( ) {if r := recover( ); r != nil {

var ok bool err, ok = r.(error) if !ok {

err = fmt.Errorf(“pkg: %v”, r) } }

}( ) fields := strings.Fields(input)

numbers = fields2numbers(fields) / / aqui panic pode ocorrer return}func fields2numbers(fields [ ]string) (numbers [ ]int) {

if len(fields) == 0 {panic(“no words to parse”)

} for idx, field := range fields {

num, err := strconv.Atoi(field) if err != nil {

panic(&ParseError{idx, field, err}) } numbers = append(numbers, num)

} return

}

Page 358: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Outro exemplo:

package mainimport (

“fmt” “./parse/parse”

)func main( ) {

var examples = [ ]string{ “1 2 3 4 5”, “100 50 25 12.5 6.25”, “2 + 2 = 4”, “1st class”, “”,

} for _, ex := range examples {

fmt.Printf(“Parsing %q:\n nums, err := parse.Parse(ex)

if err != nil { / / aqui Método String( ) a partir de ParseError é usado fmt.Println (err) continuar } fmt.Println (nums) }}/ * Saída: [1 2 3 4 5]Parsing “100 50 25 12.5 6.25”: pkg parse: error parsing “12.5” as intParsing “2 + 2 = 4”: pkg parse: error parsing “+” as intParsing “1st class”: pkg parse: error parsing “1st” as intParsing “”: pkg: no words to parse* /

Um esquema de tratamento de erros com closures

Cada vez que uma função retorna devemos testar se resultou em um erro: esta pode levar a um código repetitivo e tedioso. Combinando o mecanismo de defer/panic/recover com closures podem resultar em um esquema muito mais elegante que agora vamos discutir. No entanto, é aplicável apenas quando todas as funções têm a mesma assinatura, que é bastante restritiva. Um bom exemplo de seu uso é em aplicações web, onde todas as funções de manipulador são do seguinte tipo:

func handler1(w http.ResponseWriter, r *http.Request) { ... }

Suponha que todas as funções têm a assinatura: func f(a type1, b type2)O número de parâmetros e seus tipos é Irrelevante.Damos este tipo um nome: fType1 = func f(a type1, b type2)

Nosso esquema utiliza duas funções auxiliares:

i) check: uma função que testa se um erro ocorreu, e panics se assim for:

Page 359: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func check(err error) { if err != nil { panic(err) } }ii) esta é uma função wrapper. É preciso uma função fn do nosso tipo fType1 e retorna essa função

chamando fn.

func errorHandler(fn fType1) fType1 { return func(a type1, b type2) { defer func( ) { if e, ok := recover( ).(error); ok { log.Printf(“run time panic: %v”, err) } }( ) fn(a, b) }}

Quando ocorre um erro que está recuperado e impresso no log; além de simplesmente imprimir o aplicativo também pode produzir uma saída personalizada para o usuário usando o pacote de modelo . A função de verificação (check( ) é usado em cada função chamada, como esta:

func f1(a type1, b type2) { ... f, _, err := / / chamada de função / método check(err) t, err := / / chamada de função / método check(err) _, err2 := / / chamada de função / método check(err2) ...}

O main( ) ou outra função chamada deve então chamar as funções necessárias envolta em errorHandler, como este:

func main( ) { errorHandler(f1) errorHandler(f2) ...}

Usando este mecanismo todos os erros serão recuperados e o código de verificação de erros depois de uma chamada de função é reduzido para check(err). Neste esquema manipuladores de erro diferentes têm de ser utilizados para os diferentes tipos de funções, eles podem ser escondidos dentro de uma manipulação de erro pacote. Alternativamente uma abordagem mais geral poderia estar usando uma slice de interface vazia como parâmetro e tipo de retorno.

Iniciando um comando ou programa externo

O pacote contém o sistema operacional StartProcess função a ser chamada ou iniciar comandos OS externos ou executáveis binários, seu primeiro argumento é o processo a ser executado, o segundo pode ser usado para passar algumas opções ou argumentos, ea terceira é uma estrutura que contém informações básicas sobre o ambiente do sistema operacional.

Ele retorna o ID do processo (pid) do processo iniciado, ou um erro se ele falhou.O pacote exec contém as estruturas e funções para realizar a mesma tarefa com mais facilidade;mais importantes são exec.Command(name string, arg ...string) e Run ( ). O primeiro tem o nome de

um comando OS ou executável e cria um objeto de comando, que pode então ser executado com Run ( ) que usa esse objeto como seu receptor. O programa seguinte (que só funciona no Linux porque os comandos do Linux são executados) ilustra a sua utilização:

Page 360: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport (“fmt”

“os/exec” “os”

)func main( ) {/ / 1) os.StartProcess / //*********************//* Linux: */

env := os.Environ( ) procAttr := &os.ProcAttr{

Env: env, Files: [ ]*os.File{

os.Stdin, os.Stdout, os.Stderr,

}, }

} pid, err := os.StartProcess(“/bin/ls”, [ ]string{“ls”, “-l”}, procAttr) if err != nil {

fmt.Printf(“Error %v starting process!”, err) / / os.Exit(1)

} fmt.Printf(“The process id is %v”, pid)

/ * Saída:The process id is &{2054 0}total 2056-rwxr-xr-x 1 ivo ivo 1157555 2011-07-04 16:48 MB1_exec-rw-r--r-- 1 ivo ivo 2124 2011-07-04 16:48 MB1_exec.go-rw-r--r-- 1 ivo ivo 18528 2011-07-04 16:48 MB1_exec_go_.6-rwxr-xr-x 1 ivo ivo 913920 2011-06-03 16:13 panic.exe-rw-r--r-- 1 ivo ivo 180 2011-04-11 20:39 panic.go*/

/ / 2 º exemplo: mostrar todos os processos

pid, err = os.StartProcess(“/bin/ps”, [ ]string{“-e”, “opid,ppid,comm”}, procAttr)if err != nil {fmt.Printf(“Error %v starting process!”, err) / /os.Exit(1)}fmt.Printf(“The process id is %v”, pid)

/ / 2) cmd.Run / // *************** /

cmd := exec.Command(“gedit”) / / isso abre uma janela gedit err := cmd.Run( ) if err != nil {

fmt.Printf(“Error %v executing command!”, err) os.Exit(1)

} fmt.Printf(“The command is %v”, cmd)

Page 361: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Goroutines e Canais

Como esperado de uma linguagem de programação do século 21, Go vem com suporte embutido para comunicação entre aplicações (networking, cliente-servidor, computação distribuída) e suporte para aplicativos simultâneos. Estes são os programas que executam diferentes partes do código ao mesmo tempo, possivelmente em diferentes processadores ou computadores. Os blocos de construção básicos Go propõe para a estruturação de programas concorrentes são goroutines e canais. A sua aplicação exige o apoio da linguagem, o compilador e tempo de execução. A coleta de lixo que Go oferece também é essencial para a programação concorrente fácil.

Não se comunique através da partilha de memória. Em vez disso, compartilhar a memória por meio da comunicação.

Um aplicativo é um processo em execução em uma máquina, um processo é uma entidade de executar de forma independente que é executado em seu próprio espaço de endereço na memória. Um processo é composto de um ou mais segmentos do sistema operacional que estão sendo executadas simultaneamente entidades que compartilham o mesmo espaço de endereço.

Quase todos os programas reais são de vários segmentos, de modo a não introduzir o tempo de espera para o usuário ou o computador, ou para ser capaz de atender muitos pedidos ao mesmo tempo (como servidores web), ou para aumentar o desempenho e rendimento (por exemplo, a execução de código em paralelo em diferentes conjuntos de dados). Tal aplicação simultânea pode executar em um processador ou núcleo usando um número de threads, mas é apenas quando o mesmo processo de aplicação é executada no mesmo ponto no tempo em um número de núcleos ou processadores que é verdadeiroamente chamado paralelizado.

O paralelismo é a capacidade de fazer as coisas funcionarem rapidamente usando múltiplos processadores. Deste modo, programas simultâneos podem ou não ser paralelas.

Aplicativos multithreaded são notoriamente difíceis de acertar, o principal problema é que os dados compartilhados na memória, que podem ser manipuladas pelos diferentes segmentos de uma forma não-previsível, proporcionando assim resultados, por vezes, Irreproduzíveis e aleatórios (chamados de condições de corrida).

! Não use variáveis globais ou de memória compartilhada, eles fazem o seu código não seguro para executar simultaneamente! A solução está em sincronizar os diferentes tópicos, e trancar os dados, de modo que apenas um thread por vez pode alterar os dados. Go tem instalações para o bloqueio em sua biblioteca padrão na sincronia pacote para quando eles são necessários no código de nível inferior.Mas a experiência passada em engenharia de software mostrou que isso leva ao complexo, sujeito a erros de programação e desempenho diminuindo, por isso esta abordagem clássica não é claramente o caminho a percorrer para multicore moderno e multiprocessador de programação: o "thread-per-connection'- modelo não é quase eficiente o suficiente.

Vai aderir a outro, em muitos casos paradigmáticos mais adequado, que é conhecido como comunicação de processos seqüenciais (CSP, inventado por C. Hoare) ou também chamados a mensagem de passagem de modelo (como aplicado em outras línguas, como Erlang).

As partes de um aplicativo que executar simultaneamente são chamados goroutines em Go, que estão em virár em execução simultaneamente cálculos. Não há correspondência de um-para-um entre um goroutine e um thread do sistema operacional: a goroutine é mapeado sobre (multiplexado, executada por) um ou mais segmentos, de acordo com a sua disponibilidade, o que é realizado pelo goroutine-scheduler no Go tempo de execução.

Goroutines executado no mesmo espaço de endereço, de modo que o acesso à memória compartilhada deve ser sincronizada, o que

poderia ser feito através do pacote de sincronização, mas isso é altamente desencorajado: Vá canais de uso para sincronizar goroutines

Quando um goroutine é bloqueado por uma chamada de sistema (por exemplo, à espera de I / O), outros goroutines continuar a executar em outros segmentos. O projeto de goroutines esconde muitas das complexidades da criação e gerenciamento de threads.

Goroutines são leves, muito mais leve do que um fio. Eles têm uma pegada muito pequena (use pouca memória e recursos): eles são criados com uma memória stack-4K espaço na pilha. Porque eles são baratos para criar, um grande número deles pode ser iniciado na mosca, se necessário (na ordem de 100 milhares de pessoas no mesmo espaço de endereçamento). Além disso, eles usam uma pilha segmentado para o cultivo de forma dinâmica (ou encolhendo) sua memória-uso; empilhar gestão é automático. As pilhas não são gerenciados pelo coletor de lixo, ao invés disso eles são liberados diretamente quando as saídas goroutine.

Page 362: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Goroutines pode ser executado através de múltiplas threads do sistema operacional, mas crucialmente, eles também podem ser executados dentro de threads, permitindo-lhe lidar com mGoíade de tarefas com um consumo de memória relativamente pequena.

Goroutines time-slice em tópicos SO por assim dizer, de modo que você pode ter qualquer número de goroutines sendo atendidos por um número menor de fios do sistema operacional, eo tempo de execução Go é inteligente o suficiente para perceber qual desses goroutines está bloqueando alguma coisa e sair e fazer outra coisa.

Dois estilos de concorrência existe: determinista (ordenação bem definida) e não-determinístico (bloqueio / exclusão mútua mas a ordem não definida). Goroutines e canais da Go promover concorrência determinista (por exemplo, os canais com um remetente, um receptor), que é mais fácil de se trabalhar.

A goroutine é implementado como uma função ou método (isso também pode ser uma função anônima ou lambda) e chamado (invocado) com a palavra-chave movimento. Isso inicia a função de execução em paralelo com a computação actual, mas, no mesmo espaço de endereços e com a sua própria pilha.

A pilha de um goroutine cresce e encolhe, conforme necessário, não há possibilidade de estouro de pilha, o programador não precisa se preocupar com o tamanho da pilha. Quando o goroutine termina ele sai em silêncio:

nada é retornado para a função que começou.A função main ( ) que todos os programas de Go deve ter também pode ser visto como um goroutine,

embora não seja iniciado com movimento. Goroutines pode ser executado durante a inicialização do programa (no init ( )função).

Quando um goroutine é, por exemplo, muito muito do processador você pode chamar runtime.Gosched ( ) periodicamente em laços seu cálculo: isto produz o processador, permitindo que outros goroutines para executar, mas não suspende a goroutine atual, portanto, a execução reinicia automaticamente. Usando Gosched ( ) os cálculos são mais uniformemente distribuídos e comunicação não é fome.

A diferença entre concorrência e paralelismo

Primitivas de concorrência da Go fornecer a base para um bom desenho do programa de concorrência: expressar a estrutura do programa, de modo a representar as ações que executam de forma independente, por isso a ênfase de Go não está no 1 º lugar em paralelismo: programas concorrentes podem ou não podem ser paralelas. O paralelismo é a capacidade de fazer as coisas funcionarem rapidamente usando múltiplos processadores. Mas acontece que na maioria das vezes que um programa concorrente bem desenhado também tem excelentes capacidades paralelas desempenho.

Na atual implementação do tempo de execução (Jan 2012) Go não paralelizar código por padrão, apenas um único núcleo ou processador é dedicado a um programa de Go, independentemente de quantos goroutines são iniciados nele, assim que estes goroutines estão funcionando em simultâneo, eles não estão sendo executados em paralelo: apenas um goroutine está em execução ao mesmo tempo.

Isso provavelmente vai mudar, mas até lá, a fim de deixar o seu programa executar simultaneamente por mais núcleos, ou seja, para que goroutines estão realmente funcionando em paralelo, você tem que usar as GOMAXPROCS variáveis.

Isto indica o tempo de execução quantos goroutines deve executar simultaneamente.Também só os gc-compiladores têm uma verdadeiroa implementação de goroutines, mapeando-os em

tópicos OS conforme o caso. Com o compilador gccgo, um fio OS será criado para cada goroutine.

Usando GOMAXPROCS

De acordo com os compiladores de gc (6g ou 8G) você deve definir GOMAXPROCS a mais do que o valor padrão 1 para permitir que o suporte de tempo de execução para utilizar mais de um thread do sistema operacional, ou seja, todos goroutines compartilhar o mesmo fio, a menos GOMAXPROCS está definido para um valor maior do que 1. Quando GOMAXPROCS for maior que 1, eles correm em um pool de threads com que muitos threads.With o GOMAXPROCS compilador gccgo é efetivamente igual ao número de goroutines execução.

Suponhamos que n é o número de núcleos de transformadores ou na máquina. Se você definir o ambiente GOMAXPROCS variável> = n, ou ligue runtime.GOMAXPROCS (n), então os goroutines são divididos (distribuído) entre os n processadores. Mais processadores no entanto, não significa necessariamente uma melhora linear no desempenho, principalmente porque é necessário mais

Page 363: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

comunicação: os de transmissão de mensagens gerais aumenta. Uma regra de ouro experiencial parece ser que para n núcleos definição GOMAXPROCS a n-1

produz o melhor desempenho, e também o seguinte devem ser seguidas: número de goroutines> 1 + GOMAXPROCS> 1

Portanto, se houver apenas um goroutine execução em um determinado ponto no tempo, não deestreito GOMAXPROCS!

Aqui estão algumas outras observações de experimentos: em uma performance laptop 1 CPU melhorou quando GOMAXPROCS foi aumentado para 9. Em uma máquina de núcleo 32, o melhor desempenho foi alcançado com GOMAXPROCS = 8, um número maior não aumentou desempenho nesse benchmark.

Valores muito grandes de GOMAXPROCS degradado desempenho apenas ligeiramente, usando a opção "H" para "top" mostrou apenas 7 tópicos ativos, por GOMAXPROCS = 100.

Programas que realizam computação concorrente deverá beneficiar de um aumento no GOMAXPROCS;

ver goroutine_select2.goResumido: GOMAXPROCS é igual ao número de concorrentes ( ) tópicos, em uma máquina com mais

de um núcleo, como muitos segmentos como existem núcleos podem executar em paralelo.

Como especificar o número de núcleos para ser usado na linha de comando?

Utilizar o pacote flags, tal como em:

var numCores = flag.Int(“n”, 2, “number of CPU cores to use”)in main( ):flag.Parse( )runtime.GOMAXPROCS(*numCores)

A goroutine pode parar em si, chamando runtime.Goexit( ), embora isso raramente é necessário.

package mainimport (

“fmt” “time”

)func main( ) {

fmt.Println(“In main( )”) go longWait( ) go shortWait( ) fmt.Println(“About to sleep in main( )”) / / Sleep trabalha com um Período em nanossegundos (ns)! time.Sleep(10 * 1e9) fmt.Println(“At the end of main( )”)

}func longWait( ) {

fmt.Println(“Beginning longWait( )”) time.Sleep(5 * 1e9) / / sleep for 5 seconds fmt.Println(“End of longWait( )”)

}func shortWait( ) {

fmt.Println(“Beginning shortWait( )”) time.Sleep(2 * 1e9) / / sleep for 2 seconds fmt.Println(“End of shortWait( )”)

}

Saida:In main( )About to sleep in main( )Beginning longWait( )

Page 364: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Beginning shortWait( )End of shortWait( )End of longWait( )At the end of main( ) / / depois 10s

As três funções main ( ), longWait ( ) e shortWait ( ) são iniciados nesta ordem, como unidades de processamento independentes, e em seguida, trabalhar em paralelo. Cada função gera uma mensagem no seu início e no estreitol do seu processamento. Para simular os seus tempos de processamento, usamos a função do sono do pacote de tempo. Sleep ( ) interrompe o processamento da função ou goroutine para a quantidade indicada de tempo, o que é dado em nanossegundos (ns, o 1e9 notação representa 1 vezes 10 elevado à potência 9, e = expoente).

Eles imprimem suas mensagens na ordem em que esperamos, sempre o mesmo, mas vemos claramente que eles trabalham simultaneamente, em paralelo. Deixamos main ( ) pausa para 10s, assim temos a certeza que ele vai terminar após as duas goroutines. Se não (se deixarmos main ( ) parar por apenas 4s), main ( ) interrompe a execução mais cedo e longWait ( ) não terá a chance de ser concluído. Se não esperar em main ( ), o programa pára e as goroutines morrer com ele.

Quando a função main ( ) retorna, o programa é encerrado: não esperar por outro (não principal) goroutines para ser concluído. Essa é a razão por que, em programas de servidor, onde cada pedido é tratado por uma resposta começou como um goroutine, a função do servidor ( ) devem ser mantidos vivos. Isso geralmente é feito por iniciá-lo como um loop infinito.

Além disso goroutines são unidades independentes de execução e, quando um certo número deles começa um após o outro não pode depender de quando um goroutine Irá realmente ser iniciado. A lógica do seu código deve ser independente da ordem em que goroutines são invocados.

Para contrastar isso com um único segmento, execução sucessiva, remova o go palavras-chave, e deixar que o programa seja executado novamente.

Agora, a saída é:In main( )Beginning longWait( )End of longWait( )Beginning shortWait( )End of shortWait( )About to sleep in main( )At the end of main( ) / / depois de 17 s

Um exemplo mais útil de usar goroutines poderia ser a busca de um item em uma disposição muito grande.

Dividir a array em uma série de cortes que não se sobrepõem, e iniciar um goroutine em cada slice com o algoritmo de busca. Desta forma, um número de segmentos paralelos podem ser utilizadas para a busca para a tarefa, e o tempo de pesquisa global, certamente, ser diminuída (dividido pelo número de goroutines).

canais de comunicação entre goroutines

Em nossos primeiros exemplos os goroutines executado de forma independente, eles não se comunicam. Claro que para ser mais útil, eles têm de se comunicar: envio e recebimento de informações entre eles e coordenar / sincronizar os seus esforços. Goroutines poderia se comunicar usando variáveis compartilhadas, mas isso é altamente desencorajada, porque esta forma de trabalho apresenta todas as dificuldades com memória compartilhada em multi-threading.

Em vez Go possui um tipo especial, o canal, que é como um conduíte (tubo ou pipe) através do qual você pode enviar os valores digitados e que cuida da comunicação entre goroutines, evitando todas as armadilhas da memória compartilhada, o próprio ato de comunicação por meio de um garantias sincronização de canal. Os dados são passados em torno de canais: apenas um goroutine tem acesso a um item de dados em um determinado momento: então corridas de dados não pode ocorrer, por design. A posse dos dados (que é a capacidade de ler e escrever) é passado ao redor.

Uma analogia útil consiste em comparar um canal com um tapete transportador numa fábrica. Uma máquina (o goroutine produtor) coloca itens para o cinto, e uma máquina (o consumidor goroutine) leva-los

Page 365: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

para a embalagem.Canais servem o duplo objectivo de comunicação em troca de um valor-com que dois cálculos

(goroutines) estão em um estado conhecido em qualquer momento garantir a sincronização.A declaração de um canal é o formato geral: var identifier chan datatypeO valor do canal não inicializado é nulo.Assim, um canal só pode transmitir-itens de dados de um tipo de dados, por exemplo chan int ou

cadeia chan, mas todos os tipos podem ser utilizados em um canal, também da interface vazio { }. É até mesmo possível (e por vezes útil) para criar um canal de canais.

Um canal é, de fato, uma fila de mensagens digitada: os dados podem ser transmitidos através dele. É uma estrutura de First In First Out (FIFO) e, assim, preservar a ordem dos itens que são enviados para eles (para aqueles que estão familiarizados com ele, um canal pode ser comparado a um tubo de duas vias em conchas Unix). Um canal também é um tipo de referência, por isso temos de usar a marca ( ) para alocar memória para ele. Aqui está uma declaração de um canal ch1 de strings, seguido de sua criação (instanciação):

var ch1 chan stringch1 = make(chan string)

Mas é claro que isso pode ser reduzido para: ch1 := make(chan string)

E aqui nós construímos um canal de canais de int: chanOfChans := make(chan chan int) ou usefuncChan := chan func( )

Assim, os canais são objetos de primeira classe: eles podem ser armazenados em variáveis, passados como argumentos para funções, retornados de funções e enviou-se através de canais. Além disso, eles são digitados, permitindo que o sistema de tipo para pegar erros de programação como tentar enviar um ponteiro sobre um canal de inteiros.

Comunicação operador <-

Este operador representa muito intuitivamente a transmissão de dados: a informação flui na direção da seta.

Para um canal (envio):

ch <- int1 significa: int1 variável é enviado através do canal ch (operador binário, infixo = send)

A partir de um canal (recepção), 3 formas:

int2 = <- ch significa: int2 variável recebe dados (recebe um novo valor) a partir do ch canal (unáriooperador de prefixo, prefixo = receber), o que supõe int2 já está declarada, se não ele podeser escrita como: int2: = <- ch<- Ch pode em si mesmo ser usado para tirar o (próximo) o valor a partir do canal, este valor éeficazmente eliminada, mas podem ser testadas em cima, de modo que o código seguinte é legal:

if <-ch != 1000 {...}

O mesmo operador <- é usado para enviar e receber, mas Go descobre dependendo dos operandos o que fazer. Apesar de não ser necessário, para facilitar a leitura do nome do canal geralmente começa com ch ou contém 'chan'. O canal de enviar e receber operações são atômicas: eles sempre completa sem interruption.The uso do operador de comunicação é ilustrado no exemplo

package mainimport (

“fmt”

Page 366: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

“time”)func main( ) {

ch := make(chan string) go sendData(ch) go getData(ch) time.Sleep(1e9)

}func sendData(ch chan string) {

ch <- “Washington” ch <- “Tripoli” ch <- “London” ch <- “Beijing” ch <- “Tokio”

}func getData(ch chan string) {

var input string for {

input = <-ch fmt.Printf(“%s “, input)

}}

Saída: Washington Trípoli Londres Pequim Tokio

Em main( ) 2 goroutines foram iniciados: sendData ( ) envia 5 strings ao longo do canal ch, getData ( ) recebe-los um por um, a fim de string de entrada e imprime o que é recebido.

Se 2 goroutines tem que se comunicar, você deve dar-lhes tanto o mesmo canal como parâmetro para fazer isso.

Experimente o que acontece quando você comentar time.sleep (1e9).Aqui vemos que a sincronização entre os goroutines torna-se importante:• main( ) espera por um segundo, de modo que ambos os goroutines pode chegar a conclusão, se isso

não é permitido sendData ( ) não têm a oportunidade de produzir sua saída.• getData( ) trabalha com um infinito loop for: este chega ao fim quando sendData( ) terminou e ch está

vazio.• se remover um ou todos os go-palavras-chave, o programa não funciona mais, o tempo de execução

Go lança panic:

---- Error run E:/Go/GoBoek/code examples/chapter 14/goroutine2.exe code Crashed---- Program exited with code -2147483645: ---- Programa saiu com o código -2147483645: adormecido-impasse!

Com panic: todos são goroutines

Por que isso ocorre? O tempo de execução é capaz de detectar que todos os goroutines (ou apenas um, talvez, neste caso) estão à espera de alguma coisa (para ser capaz de ler a partir de um canal ou gravar em um canal), o que significa que o programa não pode prosseguir. Esta é uma forma de impasse, eo tempo de execução é capaz de detectá-lo para nós.

Observação:

Não use instruções de impressão para indicar a ordem de enviar para e receber a partir deum canal: este poderia ser fora de ordem com o que realmente acontece devido ao lapso de tempo

entre a declaração de impressão e do canal real de envio e recebimento.

Bloqueio de canais

Page 367: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Por padrão, a comunicação é síncrona e sem buffer: Envia não completar até que haja um receptor para aceitar o valor. Pode-se pensar em um canal sem buffer como se não há espaço no canal para dados: deve haver um receptor pronto para receber dados do canal e, em seguida, o remetente pode entregá-lo diretamente para o receptor. Assim canal enviar / receber operações bloquear até que o outro lado está pronto:

1) A operação de envio de um canal (e o goroutine ou função em que se encontra) blocos até que um receptor está disponível para o mesmo canal: se não há nenhum destinatário para o valor em ch, nenhum outro valor pode ser colocado no canal: não novo valor pode ser enviado no ch quando o canal não está vazio. Assim, a operação de envio vai esperar até ch torna-se disponível novamente: este é o caso quando o valor de canal é recebido (pode ser colocado em uma variável).

2) A operação de recebimento por blocos de canal (eo goroutine ou função em que se encontra), até que o remetente está disponível para o mesmo canal: se não há valor no canal, os blocos do receptor.

Embora isto pareça uma restrição severa, ele funciona bem na maioria das situações práticas.Isto é ilustrado na channel_block.go programa, em que a bomba goroutine envia inteiros num ciclo

infinito no canal. Mas, porque não há nenhum receptor, a única saída é o número 0.

package mainimport “fmt”func main( ) {

ch1 := make(chan int) go pump(ch1)

fmt.Println(<-ch1)}func pump(ch chan int) {

for i:= 0; ; i++ {ch <- i

}}

Saída: 0

A função da bomba ( ) que fornece os valores para o canal, por vezes é chamado um gerador.Para desbloquear o canal de definir uma função que lê suck do canal em um loop infinito, consulte a :

func suck(ch chan int) {for {

fmt.Println(<-ch) }}

e começar a isso como um goroutine em main ( ):

go pump(ch1)go suck(ch1)time.Sleep(1e9)

Dê a 1s do programa a ser executado: agora dezenas de milhares de números inteiros aparecem na saída.

Goroutines sincronizar através da troca de dados em um (ou mais) canal (s).

A comunicação é, por conseguinte, uma forma de sincronização: dois goroutines a troca de dados através de um canal de sincronização, no momento de comunicação (a rendez-vous de goroutines). Canais sem buffer tornar uma ferramenta perfeita para sincronizar múltiplas goroutines.

É ainda possível que os dois lados bloquear uns aos outros, criando o que é chamado de uma situação de impasse.

Page 368: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

O tempo de execução Go Irá detectar isto e entrar em panic, parar o programa. Um impasse é quase sempre causada por má concepção do programa.

Vemos que as operações de canal em canais sem buffer pode bloquear. A maneira de evitar isso é a concepção do programa de tal forma que o bloqueio não ocorrer, ou usando canais de buffer.

package mainimport (

“fmt”)func f1(in chan int) {

fmt.Println(<-in)}func main( ) {

out := make(chan int) out <- 2 go f1(out)

}

canais de tomada assíncronos um canal com uma memória intermédia

Um canal sem buffer pode conter apenas um item e é por essa razão, por vezes, demasiado restritiva.Podemos prever um tampão no canal, cuja capacidade de se definir em um comando estendido marca,

como esta:

buf := 100ch1 := make(chan string, buf)

buf é o número de elementos (aqui strings) do canal pode conter.Enviar para um canal tamponada não bloqueará a menos que o buffer esteja cheio (a capacidade de

utilizar completamente), e a leitura de um canal tamponada não bloqueará a menos que o buffer esteja vazio.

A capacidade tampão não pertencem ao tipo, por isso, é possível (embora talvez perirásos) para atribuir canais com diferentes capacidades para o outro, desde que eles têm o mesmo tipo de elemento.

A função cap embutido em um canal retorna essa capacidade de buffer.Se a capacidade for maior que 0, o canal é assíncrona: operações de comunicação ter sucesso sem

bloquear se o buffer não está cheio (envia) ou não vazia (recebe), e os elementos são recebidos na ordem em que são enviados. Se a capacidade é zero ou ausente, a comunicação bem-sucedida somente quando tanto um emissor e receptor estão prontas. Para sintetizar:

ch := make(chan type, value)

valor == 0 síncrona, sem buffer (Bloqueio)

valor> 0 assíncrona, tamponada (sem bloqueio) até elementos de valor

Se você usar buffers nos canais, o programa Irá reagir melhor aos aumentos repentinos de número de "pedidos": ele vai reagir mais elástica, ou com o termo oficial: vai ser mais escalável. Mas projetar seu algoritmo, em primeiro lugar com canais sem buffer, e só introduzir o buffer quando o primeiro é problemático.

goroutine usando um canal para a saída de resultado (s)

A fim de saber quando é feito um cálculo, passe um canal no qual ele pode informar. No nosso exemplo de go sum(bigArray), isso seria o mesmo que:

Page 369: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

ch := make(chan int)go sum(bigArray, ch) / / bigArray coloca a soma calculada em ch/ / … fazer outra coisa por um temposum := <-ch / / espera e recuperar a soma

Podemos também usar um canal para fins de sincronização, assim, efetivamente usá-lo como o que é chamado de um semáforo na computação tradicional. Ou, dito de outra maneira: para descobrir quando um processo (em uma goroutine) é feito, passá-lo de um canal com o qual ele pode sinalizar que é feito.

A linguagem comum usado para deixar o bloco principal do programa por tempo indeterminado, enquanto outros goroutines executar é colocar selecione { } como a última declaração em uma função principal.

Mas isso pode igualmente ser feito por meio de um canal para que o programa principal espera até que o goroutine (s) completa, o assim chamado padrão de semáforo, como discutido na secção seguinte.

Semaphore padrão

Isso é ilustrado no seguinte trecho: a computação goroutine sinaliza a sua conclusão, colocando um valor na ch canal, os principais espera de rotina sobre <-ch até que este valor fica completamente.

Por este canal que seria de esperar para obter um resultado de volta, como em:

func compute(ch chan int) { ch <- someComputation( ) / / Quando ele for concluído, o sinal no canal.} func main( ) { ch := make(chan int) / / alocar um canal. go compute(ch) / / inicia algo em um goroutine doSomethingElseForAWhile ( ) resultado: = <-ch}

Mas o sinal também pode ser outra coisa, não está ligado ao resultado, como nesta função goroutine lambda:

ch := make(chan int)go func( ) { / / doSomething ch <- 1 / / Envia um sinal, valor não importa.} ( )doSomethingElseForAWhile( )<-Ch / / Espera goroutine terminar; descartar valor enviado.

Ou neste trecho onde esperamos por 2 sort-goroutines, que cada espécie uma parte de uma slice s, acompletar:

done := make(chan bool)/ / DoSort é uma função de lambda, assim que um fecho, que conhece o canal feito:doSort := func(s [ ]int) {sort(s)done <- true}i := pivot(s)go doSort(s[:i])go doSort(s[i:])<-done<-done

Page 370: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

No seguinte trecho de código, temos um padrão full-blown semáforo onde N computações doSomething ( ) sobre uma slice de Float64 de com esse tamanho são feitas em paralelo, e um canal sem juros de exatamente o mesmo comprimento (e containining itens do tipo de interface vazio ) é sinalizada (colocando um valor nele), quando cada um dos cálculos está terminado. Para esperar por todos os goroutines ao fim, basta fazer um receptor gama de circuito sobre o canal SEM:

type Empty interface { }var empty Empty...data := make([ ]float64, N)res := make([ ]float64, N)sem := make(chan Empty, N) / / semaphore...for i, xi := range data { go func (i int, xi float64) { res[i] = doSomething(i,xi) sem <- empty } (i, xi)}/ / Espera para goroutines para terminarfor i: = 0; i <N; i + + {<-sem}

Observe a utilização do fecho: a corrente i, xi são passados para o fecho como parâmetros, mascarando as variáveis i, xi do exterior for-loop. Isso permite que cada goroutine ter sua própria cópia do i, xi, caso contrário, a próxima iteração do atualizaria loop for i, xi em todos goroutines. Por outro lado, a slice res não é passado para o fecho, uma vez que cada goroutine não precisa de uma cópia separada dele. A slice res faz parte do ambiente do fechamento, mas não é um parâmetro.

Cada iteração do loop for é feito em paralelo:

for i, v := range data { go func (i int, v float64) {

doSomething(i, v) ...

} (i, v)}

Computando as iterações de um loop for em paralelo poderia dar grandes ganhos de desempenho.Mas isso só é possível quando todas as iterações são completamente independentes uns dos outros.

Algumas línguas, como Fortaleza ou outras estruturas paralelas implementar esta como uma construção separada, em Go estes são facilmente implementados com goroutines:

A implementação de um semáforo usando um canal de buffer

Semáforos são um mecanismo muito geral de sincronização que pode ser usado para implementar semáforos (fechaduras exclusivos), limitar o acesso a vários recursos, resolver o problema dos leitores-escritores, etc Não há implementação de semáforos no pacote de sincronização do Go, mas eles podem ser facilmente emulado usando um canal de buffer:

• a capacidade do canal tamponada é o número de recursos que deseja sincronizar• o comprimento (número de elementos actualmente armazenadas) do canal é o número de recursos

actualmente a ser usado• a capacidade de menos do comprimento do canal é o número de recursos livres (o valor inteiro de

semáforos tradicionais)Nós não nos importamos com o que está armazenado no canal, apenas a sua extensão e, portanto,

vamos começar por fazer um canal que tem comprimento variável, mas 0 tamanho (em bytes):

Page 371: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

type Empty interface { }type semaphore chan Empty

Em seguida, é possível inicializar um semáforo com um valor inteiro que codifica o número de recursos disponíveis N:

sem = make(semaphore, N)

Agora nossas operações de semáforo são simples:

func (s semaphore) P(n int) { e := new(Empty) for i := 0; i < n; i++ { s <- e }}func (s semaphore) V(n int) { for i := 0; i < n; i++ { <-s }}

Isto pode por exemplo ser utilizado para implementar um mutex:

/ * Mutexes * /func (s semaphore) Lock( ) { s.P(1)}func (s semaphore) Unlock( ) { s.V(1)}/ * Sinal de espera * /func (s semaphore) Wait(n int) { s.P(n)}func (s semaphore) Signal( ) { s.V(1)}

IDIOMA: Canal padrão de fábrica

Outro padrão comum neste estilo de programação é o seguinte: em vez de passar um canal como um parâmetro para uma goroutine, deixa a função de fazer o canal e devolvê-lo (para que ele desempenha o papel de uma fábrica); dentro da função uma função lambda é chamado como um goroutine.

14,5 channel_idiom.go:

package mainimport (

“fmt” “time”

)func main( ) {

stream := pump( ) go suck(stream) )

/ / As duas linhas acima pode ser abreviado para: go suck( pump( ) ) time.Sleep(1e9)

Page 372: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}func pump( ) chan int {

ch := make(chan int) go func( ) {

for i := 0; ; i++ {ch <- i

} }( ) return ch

}

func suck(ch chan int) {for {

fmt.Println(<-ch) }}

Para gama aplicado aos canais

A cláusula de gama em loops aceita um ch canal como um operando, caso em que o loops sobreos valores recebidos do canal, assim: para v: = {gama ch fmt.Printf ("O valor é% v \ n", v)}Ele lê a partir do ch canal dado até que o canal é fechado e, em seguida, o código a seguir para

continuar a executar. Obviamente outro goroutine deve ser escrito para pc (caso contrário, os blocos de execução do loop for) e deve fechar ch quando é feito por escrito. A função de sugar pode aplicar isso e também lançar esta ação em um goroutine, nosso antirá programa torna-se agora:

package mainimport (

“fmt”“time”

)func main( ) {

suck(pump( ))time.Sleep(1e9)

}func pump( ) chan int {

ch := make(chan int)go func( ) {

for i := 0; ; i++ {ch <- i

}}( )return ch

}func suck(ch chan int) {

go func( ) {for v := range ch {

fmt.Println(v)}

}( )}

IDIOM: Canal padrão Iterator

Esse padrão utiliza o padrão anterior da Listagem 14.6 e pode ser aplicado no caso comum onde temos que preencher um canal com os itens de um tipo recipiente que contém um campo de índice de itens endereçável. Por isso, podemos definir um método que retorna um canal só de leitura de itens:

func (c *container) Iter ( ) <-chan items {

Page 373: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

ch := make(chan item) go func ( ) { for i := 0; i < c.Len( ); i++ { ch <- c.items[i] } } ( ) return ch}

Dentro do goroutine, um loop for itera sobre os elementos do recipiente c (para árvores ou gráfico algoritmos, este simples loop for poderia ser substituída por uma busca em profundidade).

O código que chama esse método pode então interagir sobre o recipiente como:

for x := range container.Iter( ) { ... }

que pode ser executado em sua própria goroutine, por isso, em seguida, o iterador acima emprega um canal e dois goroutines (que podem executar em segmentos separados). Então nós temos um padrão de produtor-consumidor típico.

Se o programa terminar antes do goroutine é feito escrever valores para o canal, então isso não será goroutine lixo coletado, o que é próprio do projeto. Este parece ser um comportamento errado, mas os canais são para threadsafe comunicação. Nesse contexto, um goroutine pendurado tentando escrever para um canal que ninguém nunca vai ler é provavelmente um bug e não algo que você gostaria de estar em silêncio coleta de lixo.

Para o padrão do Produtor-Consumidor

Suponha que temos um Produce function ( ) que fornece os valores necessários para uma função de consumir.

Ambos poderiam ser executado como um goroutine separado, Produzir colocando os valores em um canal que é lido por consumir. Todo o processo poderia ocorrer em um loop infinito:

for { Consume(Produce( ))}

Canal idirecionalidade

Um tipo de canal pode ser anotado para especificar que ele só pode enviar ou receber apenas em determinado código:

var send_only chan<- int / / canal só pode receber dadosvar recv_only <-chan int / / canal só pode enviar dados

Receba somente canais (<-chan T) não pode ser fechada, pois o fechamento de um canal pretende ser um caminho para um remetente para sinalizar que há mais valores serão enviados para o canal, por isso não tem nenhum significado para receber somente os canais. Todos os canais são criados bidirecional, mas podemos atribuí-los a idirecional variáveis de canal, como neste trecho de código:

var c = make(chan int) / / bidirecionalgo source(c)go sink(c)func source(ch chan<- int) { for { ch <- 1 }}func sink(ch <-chan int) { for { <-ch }

Page 374: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}

IDIOM: Tubulação e filtro padrão

Um exemplo mais concreto seria um processChannel goroutine que processa o que ele recebe de um canal de entrada e envia isto para um canal de saída:

sendChan := make(chan int)reciveChan := make(chan string)go processChannel(sendChan, receiveChan)func processChannel(in <-chan int, out chan<- string) {

for inValue := range in {result:= ... / / processing inValue

out <- result }

}

Usando a notação idirecionalidade temos certeza de que o goroutine não realizará operações de canais não permitidas.

Aqui está um excelente exemplo concreto e mais retiradas do Go Tutorial que imprime os números primos na sua saída, o uso de filtros ("peneiras") como seu algoritmo. 

package main import “fmt”

/ / Envia a seqüência 2, 3, 4, … para o canal ch.func generate(ch chan int) {

for i := 2; ; i++ {ch <- i / / Send i to channel ch.

}}/ / Copiar os valores de canal para canalizar para fora,/ / Removendo aqueles divisíveis por prime.func filter(in, out chan int, prime int) {

for { i := <-in / / Recebe valor da nova variável i dentro de if i%prime != 0 {

out <- i / / i Enviar para canalizar para fora. } }}

/ / A peneira principal: processos de filtragem Daisy de cadeia juntos.func main( ) {ch := make(chan int) / / Cria um novo canal.Go gerar (ch)go generate(ch) / / Start generate( ) as a goroutine.

prime := <-ch fmt.Print(prime, “ ”) ch1 := make(chan int) go filter(ch, ch1, prime) ch = ch1

}}

O filtro goroutine (entrada, saída chan int, int) nobre cópias inteiros para o canal de saída de descartar qualquer coisa divisível por prime. Assim, para cada primo um novo goroutine é lançado, trabalhando em

Page 375: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

conjunto no processo: o gerador e filtros executar concorrentemente.

Saída:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929937 941 947 953 967 971 977 983 991 997 1009 1013.......

Na segunda versão do idioma descrito acima é aplicado: as funções peneira, gerar e filtro são fábricas, eles fazem um canal e devolvê-lo, e eles usam funções lambda como goroutines.

A rotina principal agora é muito curta e clara: ela chama sieve( ), que retorna um canal contendo os números primos, e, em seguida, o canal é impresso via fmt.Println (<-primes).

Versão 2:

package mainimport “fmt”/ / Envia a seqüência 2, 3, 4, … para retorno do canalfunc generate( ) chan int {

ch := make(chan int) go func( ) {

for i := 2; ; i++ { ch <- i

} }( ) return ch

}/ / Filtrar valores de entrada divisíveis por primo, envie um descanso para o canal voltoufunc filter(in chan int, prime int) chan int {

out := make(chan int) go func( ) {

for {if i := <-in; i%prime != 0 {

out <- i } }

}( ) return out

}func sieve( ) chan int {

out := make(chan int) go func( ) {

ch := generate( ) for {

prime := <-ch ch = filter(ch, prime) out <- prime

} }( ) return out

}func main( ) {

primes := sieve( ) for {

Page 376: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

fmt.Println(<-primes) }}

Sincronização de goroutines: fechar um canal de testes para os canais bloqueados

Os canais podem ser fechados explicitamente, no entanto eles não são como arquivos: você não costuma precisar fechá-las. Encerramento de um canal só é necessária quando o receptor deve ser dito que não há mais valores próximos. Apenas o remetente deve fechar um canal, nunca o receptor.

Continuando com o exemplo goroutine2.go: como podemos sinalizar quando sendData ( ) é feito com o canal, e como pode getData ( ) detectar que o canal está fechado ou bloqueado?

O primeiro é feito com a função close (ch): esta marca o canal como incapaz de aceitar mais valores por meio de uma operação de envio <-; envio ou fechar um canal fechado provoca panic em tempo de execução.

É uma boa prática de fazer isso com uma declaração de adiamento imediatamente após a tomada do canal (Quando é apropriado em uma dada situação):

ch: = make (chan float64) defer perto (ch)defer close(ch)

O segundo é feito com a vírgula, ok operador: este testa se o canal é fechado e, em seguida, retorna true, caso contrário false.

Como podemos testar que podemos receber sem bloquear (ou que ch canal não está fechada)?

v, ok: = <-chv, ok := <-ch / / ok é verdade se v recebeu valor

Muitas vezes isso é usado em conjunto com uma instrução if:if v, ok := <-ch; ok { process(v)}

Ou quando o recebimento ocorre em um loop, use pausa quando ch é fechada ou bloqueada:

v, ok := <-chif !ok { break}process(v)

Podemos acionar o comportamento de um non-blocking enviar por escrito: _ = ch <- v porque o identificador em branco leva o que for enviar no cap, que produz a mesma saída.

Para fazer um canal sem bloqueio de leitura que você precisa usar select

package mainimport “fmt”func main( ) {

ch := make(chan string) go sendData(ch) getData(ch)

}func sendData(ch chan string) {

ch <- “Washington” ch <- “Tripoli” ch <- “London” ch <- “Beijing” ch <- “Tokio” close(ch)

Page 377: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}func getData(ch chan string) {

for { input, open := <-ch if !open {

break } fmt.Printf(“%s “, input)

}}

Aqui está o que é alterado no código:

- Só sendData( ) é agora um goroutine, getData( ) é executado no mesmo segmento como main( ):

go sendData(ch)getData(ch))

- No fim da função sendData ( ), o canal é fechado:

func sendData(ch chan string) { ch <- “Washington” ch <- “Tripoli” ch <- “London” ch <- “Beijing” ch <- “Tokio” close(ch)

}

- No loop for em getData ( ), antes de cada receber o canal é testado com

for { input, open := <-ch if !open {

break } fmt.Printf(“%s “, input)

}

É ainda melhor prática para ler o canal com uma declaração de alcance, porque este será automaticamente detectar quando o canal está fechado:

for input := range ch {process(input)

}

O bloqueio eo padrão produtor-consumidor:

No padrão de canal a partir do exercicio de iteração a relação entre os dois goroutines é de tal modo que um é geralmente um bloquear a outra. Se o programa é executado em uma máquina com vários núcleos, apenas um processador será empregue na maioria das vezes. Isto pode ser melhorado através da utilização de um canal com um tamanho de buffer maior do que 0.Por exemplo, com um tampão de tamanho 100, a iteração pode produzir pelo menos 100 itens a partir do recipiente antes de bloquear.

Se o goroutine consumidor está sendo executado em um processador separado, é possível que nem goroutine nunca Irá bloquear.

Como o número de itens no recipiente é do conhecimento geral, não faz sentido usar um canal com capacidade suficiente para armazenar todos os itens. Dessa forma, o iterador nunca Irá bloquear (embora o consumidor ainda pode goroutine). No entanto, isso efetivamente dobra a quantidade de memória

Page 378: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

necessária para repetir em qualquer recipiente dado, então a capacidade do canal deve ser limitado a um número máximo. Tempo ou de benchmarking seu código Irá ajudá-lo a encontrar a capacidade do buffer para uso de memória mínima e um ótimo desempenho.

Alternar entre goroutines com select

Obtendo os valores de diferentes goroutines executando simultaneamente pode ser realizado com a palavra-chave de seleção, que se assemelha a instrução de controle switch (Capítulo 5 § 5.3) e às vezes é chamado de comunicações switch , ele age como um, você está pronto mecanismo de votação;

selecionar escuta para os dados de entrada nos canais, mas também pode haver casos em que o valor é enviado em um canal.

select {case u:= <- ch1:

...case v:= <- ch2:

... ...

default: / / no value ready to be received...

}

A cláusula de default é opcional; caro através de um comportamento, como no switch normal, não é permitido. A seleção é encerrado quando uma pausa ou retorno é executado em um de seus casos.

O seleto faz é: ele escolhe qual das várias comunicações registradas por seus casos, pode prosseguir.• se todos são bloqueados, ele espera até que se possa proceder• se múltipla pode continuar, ele escolhe um ao acaso.• quando nenhuma das operações do canal pode prosseguir ea cláusula padrão está presente, então

este é executado: o padrão é sempre executável (ou seja: pronto para executar).Usando uma operação de envio em uma instrução SELECT com um caso padrão garante que o envio

será non-blocking! Se não houver nenhum dos casos, os blocos selecionados execução para sempre.O select-statement implementa uma espécie de ouvinte-padrão, e por isso é usado principalmente

dentro de um loop (n infinito), quando uma determinada condição é atingida, o laço é encerrado por uma instrução break.

No programa goroutine_select.go há 2 canais CH1 e CH2 e 3 goroutines pump1 ( ), pump2 ( ) e sugar ( ). Este é um padrão produtor-consumidor típico.

Em loops infinitos CH1 e CH2 são preenchidos com números inteiros através pump1 ( ) e pump2 ( ); chupar ( ) as pesquisas para a entrada também em um loop sem fim, leva os inteiros dentro de CH1 e CH2 na cláusula select, e gera-los. O caso em que é escolhido depende de qual a informação do canal é recebida. O programa é encerrado em principal, depois de 1 segundo.

package mainimport (

“fmt” “time” “runtime”

)func main( ) {

runtime.GOMAXPROCS(2) / / in goroutine_select2.go ch1 := make(chan int) ch2 := make(chan int) go pump1(ch1) go pump2(ch2) go suck(ch1, ch2) time.Sleep(1e9)

}func pump1(ch chan int) {

for i:=0; ; i++ {

Page 379: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

ch <- i*2 }}func pump2(ch chan int) {

for i:=0; ; i++ {ch <- i+5

}}func suck(ch1 chan int,ch2 chan int) {

for { select { case v:= <- ch1:

Saída: Received on channel 2: 5 Received on channel 2: 6

Received on channel 1: 0 Received on channel 2: 7 Received on channel 2: 8 Received on channel 2: 9 Received on channel 2: 10 Received on channel 1: 2 Received on channel 2: 11 ... Received on channel 2: 47404 Received on channel 1: 94346 Received on channel 1: 94348

A saída produzida em 1 s é bastante surpreendente, se considerarmos que (goroutine_select2.go) obtemos cerca de 90 mil números.

Canais, intervalos e Tickers

O pacote de tempo tem algumas funcionalidades interessantes para utilização em combinação com os canais. Ele contém um time.Ticker estrutura que é um objecto que envia repetidamente o valor do tempo em um continham canal C em um intervalo de tempo especificado:

type Ticker struct { C <-chan Time / / o canal no qual os carrapatos são entregues. / / Contém campos filtrados ou não exportadas ...}

O tempo de intervalo é especificado ns (em nanossegundos como um int64) é especificado como uma variável do tipo durante Duração no time.NewTicker função de fábrica: func NewTicker(dur) *Ticker

Ele pode ser muito útil quando, durante a execução de alguma coisa goroutines (log de um estado, uma impressão, de um cálculo, etc) tem que ser feita periodicamente, a um determinado intervalo de tempo.

O Ticker é parado com Stop( ), use esta em um comunicado de adiamento (defer). Tudo isso se encaixa muito bem em uma instrução SELECT:

ticker := time.NewTicker(updateInterval)defer ticker.Stop( )...select {case u:= <- ch1:

Page 380: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

…case v:= <- ch2:

...case <- ticker.C: logState(status) / / chama alguma função de registro logStatedefault: / / nenhum valor pronto para ser recebido ...}

A função time.Tick ( ) com a assinatura função Tick (d Duração) <-chan Tempo é útil quando você só precisa de acesso ao canal de retorno e não precisa desligar-lo: ele envia o tempo no canal de retorno com periodicidade d, que é um número de nanossegundos. Handy para usar quando você tem que limitar a taxa de processamento por unidade de tempo, como no seguinte trecho de código (o cliente função.

import “time”rate_per_sec := 10var dur Duration = 1e9 / rate_per_secchRate := time.Tick(dur) / / um carrapato cada 1/10th de um segundofor req := range requests { <- chRate / / Taxa de limitar nossas chamadas Service.Method RPC go client.Call(“Service.Method”, req, ...)}

O efeito líquido é que os novos pedidos podem apenas são tratados à taxa indicada: os blocos de canal chRate taxas mais elevadas. A taxa por segundo pode ser aumentada ou diminuída de acordo com a carga e /ou os recursos da máquina.

Um tipo de temporizador parece exatamente o mesmo como um tipo Ticker (ela é construída com NewTimer (d mas ele envia o tempo apenas uma vez, após uma duração d.

Existe também uma função time.After (d) com a assinatura: func After(d Duration) <-chan Time

Após Duração d o tempo atual é enviado no canal voltou, por isso isto é equivalente a NewTimer (d) C;. Se assemelha Tick ( ), mas depois ( ) envia o tempo apenas uma vez. A lista a seguir mostra um exemplo muito concreto, e também ilustra muito bem a cláusula padrão no select:

package mainimport (

“fmt” “time”

)func main( ) {

tick := time.Tick(1e8) boom := time.After(5e8) for {

select { case <-tick:

fmt.Println(“tick.”) case <-boom:

fmt.Println(“BOOM!”) return

default: fmt.Println(“ .”) time.Sleep(5e7)

}

Page 381: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}}

/ * Saída:.tick...tick...tick...tick...tick.BOOM!* /

IDIOM: padrão de tempo limite Simples

Queremos receber de um ch canal, mas quero esperar no máximo 1 segundo para o valor chegar.Comece criando um canal de sinalização e lançar um goroutine lambda que dorme antes de enviar no

canal:

timeout := make(chan bool, 1)go func( ) { time.Sleep(1e9) / / um segundo timeout <- true} ( )

Em seguida, use uma instrução SELECT para receber a partir de qualquer ch ou timeout: se nada chega ao chão em um período de tempo s, o caso de tempo limite é selecionado e a tentativa de ler a partir de ch é abandonado.

select {case <-ch: / / A leitura de ch ocorreucase <-timeout: / / A leitura de ch expeirou break}

Segunda variante: Abandonar chamadas síncronas que funcionam muito longo:Poderíamos também usar o time.After function ( ) em vez de um canal de tempo limite. Isto pode ser

utilizado em um select para sinalizar um tempo de espera ou parar uma execução de goroutines. Quando, no seguinte trecho de código que client.Call não retorna um valor para o canal ch depois timeoutNs ns o caso de tempo limite é executado no select:

ch := make(chan error, 1)go func( ) { ch <- client.Call(“Service.Method”, args, &reply) } ( )select {case resp := <-ch:case <-time.After(timeoutNs): break}

Note-se que o tamanho do buffer de 1 é necessário para evitar impasse de goroutines e garantir a

Page 382: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

coleta de lixo do canal de timeout.

3 ª variante: Suponha que temos um programa que lê a partir de vários bancos de dados replicados simultaneamente.

O programa precisa de apenas uma das respostas, e deve aceitar a resposta que chega em primeiro lugar. A consulta função recebe uma slice de conexões de banco de dados e uma seqüência de consulta. Examina cada um dos bancos de dados em paralelo e retorna a primeira resposta que recebe:

func Query(conns [ ]Conn, query string) Result { ch := make(chan Result, 1) for _, conn := range conns { go func(c Conn) { select { case ch <- c.DoQuery(query): default: } }(conn) } return <- ch}

Aqui, novamente, o ch canal resultado tem de ser tamponado: isso garante que o primeiro envio tem um lugar para colocar o valor e garante que ele sempre terá êxito, então o primeiro valor a chegar serão recuperados, independentemente da ordem de execução. Um goroutine execução sempre pode ser interrompido pelo telefone runtime.Goexit( )

Cache de dados em aplicações:

Os pedidos de trabalho com dados provenientes de um banco de dados (ou, em geral, um armazenamento de dados), muitas vezes, armazenar em cache os dados na memória, porque recuperar um valor de um banco de dados é uma operação custosa, quando o valor do banco de dados não muda, não há problema com isso. Mas, para valores que podem mudar, precisamos de um mecanismo que relê periodicamente o valor no banco de dados: o valor em cache, nesse caso, torna-se inválido (já expeirou) e nós não queremos que a nossa aplicação para apresentar um valor antirá para o usuário.

Usando recuperar com goroutines

Uma aplicação de recuperar é desligar um goroutine falhar dentro de um servidor sem matar os outros goroutines executoras.

func server(workChan <-chan *Work) { for work := range workChan { go safelyDo(work) }}func safelyDo(work *Work) { defer func( ) { if err := recover( ); err != nil { log.Printf(“work failed with %s in %v:”, err, work) } }( )

do(work)}

No trecho de código acima, se fazer (work) entra em panic, o erro será registrado e o goroutine saIrá limpa sem perturbar os outros goroutines.

Porque recuperar sempre retorna nulo, a menos chamado diretamente a partir de uma função diferido, código diferido pode chamar rotinas de biblioteca que se utilizam de panic e recuperar sem falhar. Como exemplo, a função adiada em safelyDo ( ) pode chamar uma função de log antes de chamar recuperar, e

Page 383: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

que o código de registro correria afetado pelo estado em panic. Com o nosso padrão de recuperação no local, a função do (e qualquer coisa que chama) pode sair de qualquer situação ruim limpa chamando panic.

Mas a recuperação tem que ocorrer dentro do goroutine em panic: ele não pode ser recuperado por um goroutine diferente.

Comparando o velho eo novo modelo: Tarefas e processos de trabalho.

Suponha que nós temos que executar uma série de tarefas, uma tarefa é executada por um trabalhador (processo). Uma tarefa pode ser definido como uma estrutura (os detalhes concretos não são importantes aqui):

type Task struct { / / Algum estado}

1 (antirá) paradigma: usar a memória compartilhada para sincronizar

O conjunto de tarefas é compartilhada da memória;, a fim de sincronizar o trabalho e evitar condições de corrida, temos que guardar a piscina com um bloqueio Mutex:

type Pool struct {Mu sync.MutexTasks [ ]Task

}

A sync.Mutex é um bloqueio de exclusão mútua: ela serve para proteger a entrada de uma seção crítica em código: apenas um goroutine (thread) pode entrar que a seção de uma vez. Se mais de um goroutine seria permitido, uma condição de corrida pode existir: a estrutura exterior não podia mais ser atualizados corretamente. No modelo tradicional (aplicado na maioria dos OO-línguas clássicas como C + +, Java, C #), o processo de trabalho poderia ser codificado como:

func Worker(pool *Pool) { for { pool.Mu.Lock( ) / / Começam seção crítica: task := pool.Tasks[0] / / Pegar a primeira tarefa pool.Tasks = pool.Tasks[1:] / / Atualiza o conjunto de tarefas / / Fim da seção crítica pool.Mu.Unlock( ) process(task) }}

Muitos desses processos de trabalho poderiam ser executados simultaneamente, pois eles certamente poderia ser iniciado como goroutines. Um trabalhador bloqueia a piscina, toma a primeira tarefa da piscina, abre a piscina, e em seguida, processa a tarefa. O bloqueio garante que apenas um processo de trabalho de cada vez pode acessar a piscina: a tarefa é atribuída a um e apenas um processo. Se o bloqueio não estaria lá, o processamento do trabalhador de rotina pode ser interrompido na tarefa linhas: = pool.Tasks [0] e pool.Tasks = pool.Tasks [1:] com resultados anormais: alguns trabalhadores não faria obter uma tarefa, algumas tarefas seria obtida por vários trabalhadores. Essa sincronização de bloqueio funciona bem para alguns processos de trabalho, mas se a piscina é muito grande e vamos atribuir um grande número de processos para trabalhar com ele, a eficiência do processamento será diminuída pela sobrecarga do mecanismo de lock-unlock. Este é o gargalo: o desempenho certamente Irá diminuir quando o número de trabalhadores aumenta, drasticamente em um determinado limite.

2 paradigma: canais

Page 384: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Agora canais de tarefas são usados para sincronizar: um canal pendente recebe as tarefas solicitadas, um canal feito recebe as tarefas realizadas (com os resultados). O processo de trabalho é iniciado como goroutines, o número N deve ser ajustada ao número de tarefas.

A rotina principal, que realiza a função de mestre, podia ser programada como:

func main( ) { pending, done := make(chan *Task), make(chan *Task) go sendWork(pending) / / tarefas de venda com o trabalho no canal for i: = 0; i <N; i + + { / / start N goroutines para fazer o trabalho go Worker(pending, done) } consumeWork (feito) / / Continuar com as tarefas processadas}

O processo de trabalho é muito simples: ter uma tarefa a partir do canal pendente, processá-lo, colocando o terminar tarefa no canal feito:

func Worker(in, out chan *Task) {for {

t := <-in process(t) out <- t

}}

Não há bloqueio: o processo de obtenção de uma nova tarefa não envolve disputa. Se a quantidade de tarefas aumenta, o número de trabalhadores pode ser aumentada em conformidade e desempenho que não se degrada tão mal quanto na primeira solução. Do canal pendente há, naturalmente, apenas 1 cópia na memória, mas não há contenção, porque a primeira Trabalhador para chegar à primeira tarefa pendente simplesmente leva-lo (leitura e envio de um canal são operações atômicas: ver § 14.2.2 ) e processá-lo completamente. É impossível prever quais tarefa será executada pela qual o processo, e vice-versa. Com um número crescente de trabalhadores, há também um aumento da comunicação

sobrecarga, que tem um pequeno impacto no desempenho.Neste exemplo simples, talvez seja difícil ver a vantagem do segundo modelo, mas as aplicações com

situações-bloqueio complexos são muito difíceis de programar e de acertar, e uma grande parte dessa complexidade no software não é necessário em uma solução que se aplica o segundo modelo.

Assim, não só o desempenho é uma grande vantagem, mas o código mais claro e elegante é, talvez, uma vantagem ainda maior. É sem dúvida uma forma idiomática Go de trabalhar:

IDIOMA: Use dentro e fora de canal ao invés de bloquear

func Worker(in, out chan *Task) {for {

t := <-in process(t) out <- t

}}

Para qualquer problema que pode ser modelado como tal paradigma Master-Worker, uma solução análoga com os trabalhadores como goroutines comunicam através de canais e o Mestre como coordenador seria um ajuste perfeito. Se o sistema distribui ao longo de várias máquinas, um número de máquinas pode executar as goroutines Trabalhadores, eo Mestre e trabalhadores pudessem se comunicar entre si através netchan ou rpc.

O que usar: a sync.Mutex ou de um canal?

Page 385: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Embora neste capítulo, sublinhou insistentemente goroutines usando canais porque isso é muito novo em idiomas do sistema, isso não significa que a abordagem clássica com bloqueio agora é tabu: Go tem tanto e dá-lhe a escolha de acordo com o problema a ser resolvido : construir a solução que é o desempenho mais elegante, simples e de fácil leitura, e na maioria dos casos vai seguir automaticamente. Não tenha medo de usar um Mutex se que se encaixa o seu problema melhor. Go é pragmático em deixá-lo usar as ferramentas que resolver o seu problema melhor e não forçá-lo em um estilo de código.

Como uma regra geral:

uso de bloqueio (mutexes), quando:

▪ cache informações em uma estrutura de dados compartilhada▪ segurando informações de estado, que é o contexto ou o estado do aplicativo em execução

usecanais quando:

▪ comunicando resultados assíncronos▪ distribuição de unidades de trabalho▪ passando propriedade dos dados

Se você encontrar suas regras de bloqueio estão ficando muito complexo, pergunte-se se o uso do canal (s) não pode ser mais simples.

Implementação de um gerador de preguiçoso

Um gerador é uma função que retorna o próximo valor em uma seqüência cada vez que a função é chamada, como:

generateInteger( ) => 0generateInteger( ) => 1generateInteger( ) => 2....

É um produtor que só retorna o próximo valor, não a seqüência inteira, o que é chamado de avaliação preguiçosa: só calcular o que você precisa no momento, poupando recursos valiosos (memória e CPU): é uma tecnologia para a avaliação de expressões na demanda. Um exemplo seria a geração de uma seqüência interminável de números pares: para gerá-la e, em seguida, usar os números um a um seria talvez difícil e certamente não Iria caber na memória! Mas uma função simples por tipo com um canal e uma goroutine pode fazer o trabalho.

package mainimport (

“fmt”)var resume chan intfunc integers( ) chan int { yield := make (chan int) count := 0 go func ( ) { for { yield <- count count++ } } ( ) return yield}func generateInteger( ) int { return <-resume

Page 386: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

} func main( ) { resume = integers( ) fmt.Println(generateInteger( )) / /=> 0 fmt.Println(generateInteger( )) / /=> 1 fmt.Println(generateInteger( )) / /=> 2}

Uma diferença subtil é que o valor lido a partir do canal poderia ter sido gerado algum tempo atrás, não é gerada no momento da leitura. Se você precisa de um tal comportamento, você tem que implementar um mecanismo de solicitação-resposta. Quando a tarefa do gerador é computacionalmente caro eo fim de gerar resultados, não importa, em seguida, o gerador pode ser paralelizado internamente usando goroutines. Mas tome cuidado para que a sobrecarga gerada pela desova muitos goroutines não superam qualquer ganho de desempenho.

Estes princípios podem ser generalizada: por meio da utilização inteligente da interface vazia, fechamentos e funções de alta ordem, podemos implementar um BuildLazyEvaluator construtor genérico para a função de avaliação preguiçosa (isto deve melhor colocado dentro de um pacote de utilitários). O construtor tem uma função que tem de ser avaliado e um estado inicial como argumentos e retorna uma função sem argumentos retornando o valor desejado. A função de avaliação passou tem de calcular o próximo valor de retorno, bem como o próximo estado com base no argumento do Estado. Dentro do construtor de um canal e uma goroutine com um loop infinito são criados. Os valores de retorno são transmitidos para o canal a partir do qual eles são obtidos pela

a função retornou para uso posterior. Cada vez que um valor é buscado o próximo vai ser calculado.No próximo exemplo, este é aplicado através da definição de um whitch evenFunc preguiçosamente

gera números pares:Em main( ), criamos os primeiros 10 números pares, a cada novo convite ao mesmo ( ) retorna o

próximo. Para isso, teve de se especializar a nossa função de construção em geral BuildLazyIntEvaluator, em seguida, fomos capazes de definir até mesmo em cima disso.

package mainimport (

“fmt”)type Any interface{ }type EvalFunc func(Any) (Any, Any)func main( ) {

evenFunc := func(state Any) (Any, Any) { os := state.(int) ns := os + 2 return os, ns

} even := BuildLazyIntEvaluator(evenFunc, 0) for i := 0; i < 10; i++ {

fmt.Printf(“%vth even: %v\n”, i, even( )) }}func BuildLazyEvaluator(evalFunc EvalFunc, initState Any) func( ) Any {

retValChan := make(chan Any) loopFunc := func( ) {

var actState Any = initState var retVal Any for {

retVal, actState = evalFunc(actState) retValChan <- retVal

} } retFunc := func( ) Any {

Page 387: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

return <-retValChan } go loopFunc( ) return retFunc

}func BuildLazyIntEvaluator(evalFunc EvalFunc, initState Any) func( ) int {

ef := BuildLazyEvaluator(evalFunc, initState) return func( ) int {

return ef( ).(int) }}

/ * Saída:0th even: 01th even: 22th even: 43th even: 64th even: 85th even: 106th even: 127th even: 148th even: 169th even: 18* /

Futuros de execução

A ideia relacionada é a de futuros: às vezes você sabe que precisa para calcular um valor antes que você precise realmente usar o valor. Neste caso, você pode potencialmente iniciar calcular o valor em outro processador e tê-lo pronto quando você precisar dele.

Futuros são fáceis de implementar via encerramentos e goroutines, a idéia é semelhante aos geradores, com exceção de necessidades futuras para retornar somente um valor.

Suponha que temos uma array de tipo e precisamos calcular o inverso do produto de duas arrays A e B, primeiro temos que inverter os dois através de uma função inversa (m), e, em seguida, levar o produto de ambos os resultados. Isto poderia ser feito com a seguinte função InverseProduct( ):

func InverseProduct(a Matrix, b Matrix) { a_inv := Inverse(a) b_inv := Inverse(b) return Product(a_inv, b_inv)}

Neste exemplo, sabe-se, inicialmente, que o inverso de ambos A e B deve ser calculado. Por que o programa espere a_inv a ser calculado antes de iniciar o cálculo do b_inv?

Estes cálculos inversas podem ser feitas em paralelo. Por outro lado, a chamada para o Produto precisa esperar tanto para a_inv e b_inv para terminar. Isto pode ser implementada como se segue:

func InverseProduct(a Matrix, b Matrix) { a_inv_future := InverseFuture(a) / / Começou como um goroutine b_inv_future := InverseFuture(b) / / Começou como um goroutine a_inv := <-a_inv_future b_inv := <-b_inv_future return Product(a_inv, b_inv)}

onde InverseFuture( ) lança uma tampa tal como uma goroutine, o que coloca a array inversa resultante num futuro canal como resultado:

Page 388: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func InverseFuture(a Matrix) { future := make(chan Matrix) go func( ) { future <- Inverse(a) }( ) return future}

Ao desenvolver um pacote computacionalmente intensivo, pode fazer sentido para projetar toda a API em torno de futuros. O futuro pode ser usado dentro de seu pacote, mantendo uma API amigável. Além disso, os futuros pode ser exposto através de uma versão assíncrona do API. Desta forma, o paralelismo em seu pacote pode ser levantado no código do usuário com o mínimo esforço.

Multiplexing

Aplicações cliente-servidor é o tipo de aplicações onde goroutines e canais de brilhar.Um cliente pode ser qualquer programa em execução em qualquer dispositivo que precisa de algo a

partir de um servidor, então ele envia um pedido. O servidor recebe o pedido, faz algum trabalho e, em seguida, envia uma resposta de volta para o cliente. Em uma situação típica há muitos clientes (tantos pedidos) e um (ou alguns) servidores. Um exemplo que usamos o tempo todo é o navegador do cliente, que solicita uma página web. Um servidor web responde enviando a página web de volta para o navegador.

Em Go um servidor Irá normalmente executam uma resposta a um cliente em um goroutine, portanto, um goroutine é lançado para cada solicitação do cliente. A técnica comumente usada é que o próprio cliente-pedido contém um canal, que o servidor usa para enviar sua resposta.

Por exemplo, o pedido é uma estrutura como a seguinte, que incorpora um canal de resposta:

type Request struct { a, b int; replyc chan int;replyc chan int; / / Resposta do canal dentro da Solicitação}

Ou de modo mais geral:

type Reply struct { ... }type Request struct {arg1, arg2, arg3 some_typereplyc chan *Reply}

Continuando com a forma simples, o servidor poderia lançar para cada pedido uma corrida function ( ) em um goroutine que Irá aplicar um op operação do tipo binOp aos ints e, em seguida, enviar o resultado no canal de resposta:

type binOp func(a, b int) intfunc run(op binOp, req *Request) { req.replyc <- op(req.a, req.b)}

A rotina de servidor laços para sempre, receber pedidos a partir de uma solicitação chan * e, para evitar o bloqueio devido a uma operação de longa duração, iniciando uma goroutine para cada solicitação para fazer o trabalho real:

func server(op binOp, service chan *Request) { for { req := <-service; / / pedidos chegam aqui / / Inicia goroutine para pedido: go run(op, req); }}

Page 389: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

O servidor é iniciado em seu próprio goroutine pelo startServer função:

func startServer(op binOp) chan *Request { reqChan := make(chan *Request); go server(op, reqChan); return reqChan;}

startServer será invocado na rotina principal.

No seguinte teste exemplo, 100 solicitações são enviadas para o servidor, só depois de todos eles terem sido enviados podemos verificar as respostas na ordem inversa:

func main( ) { adder := startServer(func(a, b int) int { return a + b }) const N = 100 var reqs [N]Request for i := 0; i < N; i++ {

req := &reqs[i] req.a = i req.b = i + N req.replyc = make(chan int) adder <- req / / Somador é um canal de pedidos

} / / verifica: for i := N - 1; i >= 0; i-- { / / Não importa que ordem

if <-reqs[i].replyc != N+2*i { fmt.Println(“fail at”, i) } else {

fmt.Println(“Request “, i, “is ok!”)}

} fmt.Println(“done”)

}

O código pode ser encontrado na Listagem, a saída é:

Request 99 is ok!Request 98 is ok!...Request 1 is ok!Request 0 is ok!Done

Este programa só começa 100 goroutines. Execute o programa para 100 mil goroutines, e mesmo assim vê-se que ele termina em poucos segundos. Isso demonstra como goroutines leves são: se quisermos começar a mesma quantidade de fios de reais, o programa trava rapidamente.

package mainimport “fmt”type Request struct {

a, b int replyc chan int / / resposta do canal dentro da Solicitação}type binOp func(a, b int) intfunc run(op binOp, req *Request) {

req.replyc <- op(req.a, req.b)}func server(op binOp, service chan *Request) {

Page 390: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

for { req := <-service / / pedidos chegam aqui

/ / Inicia goroutine para pedido: go run(op, req) / / não espere por op }}func startServer(op binOp) chan *Request {

reqChan := make(chan *Request)go server(op, reqChan)return reqChan

}func main( ) {

adder := startServer(func(a, b int) int { return a + b })const N = 100var reqs [N]Requestfor i := 0; i < N; i++ {

req := &reqs[i]req.a = ireq.b = i + Nreq.replyc = make(chan int)adder <- req

}/ / verifica:for i := N - 1; i >= 0; i-- { / / Não importa que ordem

if <-reqs[i].replyc != N+2*i {fmt.Println(“fail at”, i)} else {

fmt.Println(“Request “, i, “is ok!”)}

}fmt.Println(“done”)

}

14.10.2 subdivisão: desligar o servidor por um canal de sinalização

Na versão anterior, o servidor não faz um desligamento normal quando principal retorna, ele é forçado a parar.Para melhorar isso, podemos fornecer uma segunda, saia do canal para o servidor:

func startServer(op binOp) (service chan *Request, quit chan bool) { service = make(chan *Request) quit = make(chan bool) go server(op,service,quit) return service, quit

}

A função do servidor, em seguida, usa uma seleção para escolher entre o canal de serviço e saircanal:

func server(op binOp, service chan *request, quit chan bool) {for { select { case req := <-service:

go run(op, req) case <-quit: return } }}

Quando um valor de verdade entra no canal de sair, o servidor retorna e termina.

Page 391: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Na principal, altere a seguinte linha:

adder, quit := startServer(func(a, b int) int { return a + b })

No estreitol do principal, coloque a linha: quit <- true

O código completo pode ser encontrado em multiplex_server2.go, com o mesmo resultado.

package mainimport “fmt”type Request struct {

a, b replyc chan int / / resposta do canal dentro da Solicitação

}type binOp func(a, b int) intfunc run(op binOp, req *Request) {

req.replyc <- op(req.a, req.b)}func server(op binOp, service chan *Request, quit chan bool) {

for { select { case req := <-service:

go run(op, req) case <-quit: return } }}func startServer(op binOp) (service chan *Request, quit chan bool) {

service = make(chan *Request) quit = make(chan bool) go server(op, service, quit) return service, quit

}func main( ) {

adder, quit := startServer(func(a, b int) int { return a + b }) const N = 100 var reqs [N]Request for i := 0; i < N; i++ {

req := &reqs[i] req.a = i req.b = i + N req.replyc = make(chan int) adder <- req

} for i := N - 1; i >= 0; i-- { / / doesn’t matter what order

if <-reqs[i].replyc != N+2*i {fmt.Println(“fail at”, i)

} else {fmt.Println(“Request “, i, “is ok!”)

} } quit <- true fmt.Println(“done”)

}

Limitando o número de pedidos processados simultaneamente

Page 392: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Isto é facilmente conseguido através de um canal com um tampão , cuja capacidade é o número máximo de solicitações simultâneas. O max_tasks.go programa não faz nada útil, mas contém a técnica para fazer exatamente isso: não mais do que pedidos MAXREQS serão tratadas e processadas simultaneamente, porque quando o buffer do canal SEM é completo, os blocos de função do punho e não outro pedido pode começar , até que um pedido seja removido sem. SEM age como um semáforo, um termo técnico para uma variável de sinalizador em um programa que sinaliza uma certa condição.

package mainconst ( AvailableMemory = 10 << 20 / / 10 MB, por exemplo AverageMemoryPerRequest = 10 << 10 / / 10 KB MAXREQS = AvailableMemory / AverageMemoryPerRequest / / aqui equivale a 1000)var sem = make(chan int, MAXREQS)type Request struct {

a, b int replyc chan int

}func process(r *Request) { / / Faça alguma coisa / / Pode demorar muito tempo e usar muita memória ou CPU}func handle(r *Request) { process(r) / / Sinal feito: permitir próxima solicitação para começar / / Fazendo um lugar vazio no buffer <-Sem}func Server(queue chan *Request) { for { sem <- 1 / / bloqueia quando o canal está cheio (1000 pedidos são ativos) / / So esperar aqui até que haja capacidade para processar um pedido / / (Não importa o que colocamos nele)request := <-queue go handle(request) }}func main( ) {

queue := make(chan *Request) go Server(queue)

}

Desta forma, a aplicação efectua uma utilização óptima de um recurso limitado tal como a memória, tendo goroutines sincronizar o seu uso de recursos que usando um canal tamponada (o canal é usado como um semáforo).

goroutines Encadeamento

A seguir chaining.go-programa de demonstração demonstra mais uma vez o quão fácil é para iniciar um grande número de goroutines. Aqui isso acontece em um loop para-in principal.Após o ciclo 0 é inserido no canal da direita, as 100.000 goroutines executar, e o resultado é que 100000 é impresso em menos de 1,5 s.

Este programa também demonstra como o número de goroutines podem ser dadas na linha de comando e analisado através flag.Int, por exemplo, encadeando-n = 7000 gera 7000 goroutines.

Page 393: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport (

“flag” “fmt”

)var ngoroutine = flag.Int(“n”, 100000, “how many goroutines”)func f(left, right chan int) { left <- 1+<-right }func main( ) {

flag.Parse( ) leftmost := make(chan int) var left, right chan int = nil, leftmost for i := 0; i < *ngoroutine; i++ {

left, right = right, make(chan int) go f(left, right)

} right <- 0 / / Iniciar o encadeamento

x := <-leftmost / / aguardar a conclusão fmt.Println(x) / / 100000, aprox. 1,5 s}

paralelização um cálculo ao longo de vários núcleos

Suponha que temos número NCPU de núcleos de CPU: const NCPU = 4 / / por exemplo, 4 para um processador quadqore e queremos dividir a computação em partes NCPU, cada um rodando em paralelo com os outros.

Isso poderia ser feito de forma esquemática (deixamos de lado os parâmetros concretos) como segue:

func DoAll( ) { sem := make(chan int, NCPU) / / Buffer opcional, mas sensato. for i := 0; i < NCPU; i++ { go DoPart(sem)}/ / Escorra o canal sem, à espera de tarefas para completar NCPUfor i := 0; i < NCPU; i++ { <-Sem / / Espera por uma tarefa para completar}/ / Tudo feito.}func DoPart (SEM chan int) { / / Faz a parte da computação}SEM <- 1/ / Sinal que esta peça é feita}func main( ) {

runtime.GOMAXPROCS = NCPU DoAll( )

}

- A função DOALL ( ) faz com que um canal sem juros no qual cada uma das computações paralelas vai sinalizar a sua conclusão, em um para goroutines NCPU laço são iniciados, cada um realizando 1/NCPU

- ª parte do trabalho total. Cada goroutine DoPart( ) sinaliza a sua conclusão em sem.- DOALL ( ) espera em um loop for até que todos os goroutines NCPU ter concluído: o canal sem juros

funciona como um semáforo, o código mostra um padrão típico de semáforo.No modelo atual do tempo de execução, você também tem que definir GOMAXPROCS para NCPU.

Paralelização uma computação através de uma grande quantidade de dados

Page 394: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Suponha que temos de processar um grande número de itens-de dados independentes uns dos outros, entrando através de uma no canal, e quando completamente processado colocar em um canal fora, muito parecido com um gasoduto de fábrica. O processamento de cada item de dados-provavelmente também envolvem uma série de etapas: Preprocess / STEPA / o passo B / .../ PostProcess

Um algoritmo pipelining seqüencial típico para resolver este execução de cada etapa, a fim poderia ser escrito da seguinte forma:

func SerialProcessData (in <- chan *Data, out <- chan *Data) {for data := range in {

tmpA := PreprocessData(data)tmpB := ProcessStepA(tmpA)

tmpC := ProcessStepB(tmpB) out <- PostProcessData(tmpC) }}

Apenas um passo é executado de cada vez, e cada item é processado em sequência: o processamento do segundo item não é iniciado antes do primeiro item é pós-processada eo resultado colocado no canal para fora.

Se você pensar sobre isso, você vai logo perceber que este é um gigantesco desperdício de tempo.Um cálculo muito mais eficiente seria a de deixar que cada trabalho etapa de processamento

independentes um do outro como um goroutine.Cada passo obtém os dados de entrada do canal de saída da etapa anterior. Dessa forma, a menor quantidade de tempo será perdido, e na maioria das vezes todas as etapas será ocupado executando:

func ParallelProcessData (in <- chan *Data, out <- chan *Data) {/ / Fazer canais:preOut := make(chan *Data, 100)stepAOut := make(chan *Data, 100)stepBOut := make(chan *Data, 100)stepCOut := make(chan *Data, 100)/ / Inicia computações paralelas:go PreprocessData(in, preOut)go ProcessStepA(preOut, stepAOut)go ProcessStepB(stepAOut, stepBOut)go ProcessStepC(stepBOut, stepCOut)go PostProcessData(stepCOut, out

}

As capacidades tampão canais poderia ser utilizada para optimizar ainda mais o processo inteiro.

acesso simultâneo para objetos usando um canal.

Para salvaguardar modificações concorrentes de um objeto em vez de usar o bloqueio com um Mutex sync também podemos usar um goroutine backend para a execução seqüencial de funções anônimas.

No programa seguinte, temos um tipo de pessoa que agora contém um CHF campo, um canal de funções anônimas. Este é inicializado no construtor método NewPerson, que também inicia um método de back-end ( ) como um método goroutine.This executa em um loop infinito de todas as funções colocado no CHF, efetivamente serialização los e, assim, proporcionar o acesso simultâneo seguro. Os métodos que mudam e recuperar o salário fazer uma função anônima que faz isso e colocar essa função no ICC, e backend ( ) Irá executá-las seqüencialmente. Observe como no método Salário a função de fechamento criado inclui o canal fChan.

Este é, naturalmente, um exemplo simplificado e não deve ser aplicada em tais casos, mas mostra como o problema poderia ser enfrentado em situações mais complexas.

package mainimport (

“fmt”

Page 395: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

“strconv”)type Person struct {

Name string salary float64 chF chan func( )

}func NewPerson(name string, salary float64) *Person {

p := &Person{name, salary, make(chan func( ))} go p.backend( ) return p

}func (p *Person) backend( ) {

for f := range p.chF { f( )

}}/ / Set salary.func (p *Person) SetSalary(sal float64) {

p.chF <- func( ) { p.salary = sal }}/ / Retrieve salary.func (p *Person) Salary( ) float64 {

fChan := make(chan float64)p.chF <- func( ) { fChan <- p.salary }return <-fChan

}func (p *Person) String( ) string {

return “Person - name is: ” + p.Name + “ - salary is: ” + strconv.FormatFloat(p.Salary( ), ‘f’, 2, 64)

}func main( ) {

bs := NewPerson(“Smith Bill”, 2500.5)fmt.Println(bs)bs.SetSalary(4000.25)fmt.Println(“Salary changed:”)fmt.Println(bs)

}

/*saida:Person - name is: Smith Bill - salary is: 2500.50Salary changed:Person - name is: Smith Bill - salary is: 4000.25 */

Comum Go armadilhas ou erros

No texto anterior, às vezes advertido com! ... ! por uso indevido Go. Então não se esqueça de olhar para a seção específica no livro sobre o assunto quando se deparar com uma dificuldade em uma situação como essa codificação. Aqui está uma visão geral de armadilhas para a sua conveniência, referindo-se ao local onde você pode encontrar mais explicações e exemplos:

Nunca use var p * a não confundir declaração de ponteiro e de multiplicação Nunca mude a contra-variável no loop for em si Nunca use o valor em um loop for-gama para alterar o valor em si Nunca usar goto com uma etiqueta anterior Nunca se esqueça ( ) depois de uma função de nome (capítulo 6), especificamente ao chamar um

método em um

Page 396: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

receptor ou chamando uma função lambda como um goroutine Nunca use new ( ) com mapas, sempre se Ao codificar um método ( ) String para um tipo, não use fmt.Print ou iguais no código Nunca se esqueça de usar Flush ( ) quando terminar a escrita tamponado Nunca ignore os erros, ignorá-los pode levar a falhas no programa Não use variáveis globais ou de memória compartilhada, eles fazem o seu código não seguro para a

execução de simultaneamente Use println apenas para fins de depuração

Melhores práticas: Em contraste use o seguinte:

Inicializar uma slice de mapas da maneira certa Sempre use a vírgula, forma ok (ou marcada) para o tipo de afirmações Faça e inicializar os seus tipos com uma fábrica Use um ponteiro como receptor para um método em um struct apenas quando o método modifica a

estrutura, caso contrário, use um valor

Neste capítulo vamos montar alguns dos erros mais comuns ou-não está no Go-programação.Nós muitas vezes referem-se a explicação completa e exemplos nos capítulos anteriores.Leia os títulos de parágrafo como o que você não deve fazer!

Hiding (sombreamento) uma variável por abusar curta declaração.

var remember bool = falseif something {

remember := true / / Errado.}/ / Uso lembrar

No trecho anterior do código a variável lembrar nunca se tornará realidade fora do corpo if.

Se algo é verdadeiroo, dentro do corpo, se uma nova variável lembrar que esconde o exterior lembrar é declarado por causa de: =, e não será verdade. Mas após o encerramento} de se lembrar recupera o seu valor externo falsa. Então escreva-o como:

if something {remember = true

}

Isso também pode ocorrer com um loop for, e pode ser particularmente sutil em funções com variáveis de retorno nomeados, conforme o trecho a seguir mostra:

func shadow( ) (err error) { x, err := check1( ) / / x é criado; err é atribuído a if err != nil {

return / / errar corretamente retornou} if y, err := check2(x); err != nil { / / err y e interior são criados return } else {

fmt.Println(y) } return}

Page 397: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

strings abusar.

Quando você precisa fazer um monte de manipulações em uma string, mente que strings em Go (como em Java e C #) são imutáveis. Concatenações de string do tipo a + = b são ineficientes, especialmente quando realizada dentro de um loop. Eles causam inúmeros realocações e cópia de memória. Em vez disso, deve-se usar um bytes.Buffer acumular conteúdo da string, como no seguinte trecho:

var b bytes.Buffer...for condition {

b.WriteString(str) / / Anexa string str para o buffer}return b.String( )

Observação:

Devido a compilador-optimizações e, dependendo do tamanho das cadeias usando um tampão de só começa a tornar-se mais eficiente quando o número de iterações é> 15.

Usando Defer para fechar um arquivo no âmbito errado.

Suponha que você está processando uma série de arquivos em um loop for, e você quer certificar-se de que os arquivos são fechados após o processamento usando defer, como este:

for _, file := range files { if f, err = os.Open(file); err != nil { return } / / Isto é /errado/. O arquivo não é fechado quando esta iteração do loop termina. defer f.Close( ) / / Executar operações em f: f.Process(data)}

Mas no estreitol da defer para-loop não é executado, de modo que os arquivos não estão fechados! A coleta de lixo, provavelmente, fechá-las para você, mas pode produzir erros. Melhor fazê-lo assim:

for _, file := range files { if f, err = os.Open(file); err != nil { return } / / Executar operações em f: f.Process(data) / / Fecha f: f.close ( )}

Defer só é executado no retorno de uma função, e não no estreitol de um loop ou algum outro escopo limitado.

Uma slice, como vimos, é um ponteiro para uma array subjacente. Passando uma slice como um parâmetro para uma função é provavelmente o que você sempre quis saber: passando um ponteiro para uma variável a ser capaz de mudá-lo, e não passar uma cópia dos dados.

Então você quer fazer isso:

Page 398: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

func findBiggest( listOfNumbers [ ]int ) int { }Não isso: func findBiggest( listOfNumbers *[ ]int ) int { }

Não desreferenciava uma slice quando usado como parâmetro!

Usando ponteiros para fazer a interface tipos

Olhe para o seguinte programa: Nexter é uma interface com um método next( ) significado ler o próximo byte.nextFew1 tem este tipo de interface como parâmetro e lê os próximos bytes num, devolvê-los como uma slice: isso é ok. No entanto nextFew2 usa um ponteiro para o tipo de interface como parâmetro: quando utilizar a função seguinte ( ), obtemos um erro de compilação claro: n.next indefinido (tipo * Nexter não tem campo ou método seguinte)

package mainimport ( “fmt”)type nexter interface { next( ) byte}func nextFew1(n nexter, num int) [ ]byte { var b [ ]byte for i:=0; i < num; i++ { b[i] = n.next( ) } return b}func nextFew2(n *nexter, num int) [ ]byte { var b [ ]byte for i:=0; i < num; i++ {b[i] = n.next( ) / / compile error: }return b}func main( ) { fmt.Println(“Hello World!”)}

Assim, nunca use um ponteiro para um tipo de interface, isso já é um ponteiro!

Passar um valor como um parâmetro em uma função ou como receptor de um método pode parecer um desvio de memória, porque um valor é sempre copiado. Mas, por outro lado valores são alocados na pilha, que é rápido e relativamente barato. Se você passar um ponteiro para o valor em vez do compilador Go na maioria dos casos vai ver isso como a realização de um objeto, e vai passar esse objeto para a pilha, assim também causando uma alocação de memória adicional: portanto, nada foi ganho no uso de uma ponteiro em vez do valor!

Usando fechamentos com goroutines

Olhe para o seguinte código:

Page 399: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

package mainimport (

“fmt” “time”

)var values = [5]int{10, 11, 12, 13, 14}func main( ) { / / Versão A: for ix := range values { / / Ix é o índice func( ) { fmt.Print(ix, “ ”) } ( ) / / Encerramento de chamadas, imprime cada índice } fmt.Println ) / / Versão B: mesmo que A, mas encerramento do convite como um goroutine for ix := range values { go func( ) { fmt.Print (ix, "") } ( ) } fmt.Println ( ) time.sleep (5E9) / / Versão C: o caminho certo for ix := range values {

go func(ix interface{ }) { fmt.Print(ix, “ ”)

}(ix) } fmt.Println( ) time.Sleep(5e9) / / Versão D: imprimir os valores: val := values[ix] go func( ) { fmt.Print(val, “ ”) } ( )}time.sleep(1e9)}

/ * Resultado:0 1 2 3 44 4 4 4 41 0 3 4 210 11 12 13 14* /

Versão A chama 5 vezes um fechamento que imprime o valor do índice, versão B faz o mesmo, mas invoca cada fechamento como um goroutine, argumenting que este seria mais rápido porque o fechamento executar em paralelo. Se deixar tempo suficiente para todos os goroutines para executar, a saída de versão B é: 4 4 4 4 4. Por que isso? A variável ix no circuito acima B é na verdade uma única variável que assume o índice de cada elemento da array. Porque os fechamentos são todos apenas obrigado a que uma variável, há uma boa chance de que quando você executar este código, você verá o último índice (4) impresso para cada iteração em vez de cada índice em seqüência, porque os goroutines provavelmente não iniciar a execução até que o loop, quando ix tem o valor 4.

O caminho certo para codificar esse ciclo é a versão C: invocar cada fechamento com ix como parâmetro. IX é, em seguida, avaliado em cada iteração e é colocado na pilha para o goroutine, de modo que cada índice está disponível para o goroutine quando é eventualmente executado. Note-se que a saída pode ser 0 1 2 3 4 ou 0 3 1 2 4 ou . . . , Dependendo de quando cada um dos goroutines pode começar.

Na versão D que imprimir os valores da array, por que esse trabalho e versão B não tem?Porque as variáveis declaradas dentro do corpo de um loop (como aqui val) não são partilhadas entre

Page 400: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

iterações, e, portanto, pode ser usado separadamente em um encerramento.

erro no tratamento de erro

Não use booleanos:

Fazendo uma variável booleana cujo valor é um teste no erro de condição como na seguinte ésupérfluo: var good bool

/ / Teste para um erro, bem se torna verdadeiroo ou falsoif !good { return errors.New(“things aren’t good”)}

Teste sobre o erro de imediato:

... err1 := api.Func1( )if err1 != nil { ... }

Não desorganização seu código com verificação de erros:

Evite escrever código como este:

... err1 := api.Func1( )if err1 != nil { fmt.Println(“err: “ + err.Error( )) return}

err2 := api.Func2( )if err2 != nil {...return}

Primeiro incluir a chamada para as funções em uma instrução de inicialização do if 's.Mas, mesmo assim, os erros são relatados (por imprimi-los) com instruções if espalhados por todo o

código. Com este padrão, é difícil dizer o que é a lógica normal do programa e qual é a verificação de erros / relatórios. Note também que a maior parte do código é dedicado a condições de erro em qualquer ponto do código. Uma boa solução é envolver as condições de erro em um fechamento, sempre que possível, como no exemplo a seguir:

func httpRequestHandler(w http.ResponseWriter, req *http.Request) {err := func ( ) error { if req.Method != “GET” { return errors.New(“expected GET”) } if input := parseInput(req); input != “command” { return errors.New(“malformed command”)}

/ / outro erro Condicional pode ser testado aqui } ( ) if err != nil { w.WriteHeader(400) io.WriteString(w, err) return }doSomething( ) ...

Page 401: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Essa abordagem separa claramente a verificação de erros, o relatório de erros, ea lógica normal do programa.

Ultilidade para performace - Conselho

Strings

(1) Como mudar um caractere em uma string:

str:=“hello”c:=[ ]byte(s)c[0]=’c’s2:= string(c) / / s2 == "cello"

(2) Como tomar uma parte (substring) de uma string str:

substr := str[n:m]

(3) Como varrer uma string str com para ou-range:

/ / Dá apenas o bytes:for i: = 0; i <len (str); i + + {... = str[i]}

/ / Dá os caracteres Unicode:

for ix, ch := range str {...}

(4) Número de bytes em uma string str: len (str)Número de caracteres em uma string str:MAIS RÁPIDO: utf8.RuneCountInString(str)len ([ ] int (str))

(5) A concatenação de strings:MAIS RÁPIDO: com um bytes.BufferStrings.Join( )+ =

(6) Como analisar os argumentos da linha de comando: usar o pacote de sistema operacional ou flag

Arrays e slices

Fazer: arr1 := new([len]type) slice1 := make([ ]type, len)

Inicialização: arr1 := [...]type{i1, i2, i3, i4, i5} arrKeyValue := [len]type{i1: val1, i2: val2} var slice1 [ ]type = arr1[start:end]

(1) Como cortar o último elemento de uma array ou linha slice: line = line[:len(line)-1]

Page 402: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

(2) Como fazer um loop sobre uma array (ou slice) arr por ou para-range:

for i:=0; i < len(arr); i++ { ... = arr[i]

}for ix, value := range arr { ... }

(3) Procurar um valor V em um 2 dimensionais array/slice arr2Dim:

found := falseFound: for row := range arr2Dim { for column := range arr2Dim[row] if arr2Dim[row][column] == V found = true break Found } }}

Mapas

Fazer: map1 := make(map[keytype]valuetype)Inicialização: map1 := map[string]int{“one”: 1, “two”: 2}

(1) Como fazer loop para um mapa map1 por, intervalo:

for key, value := range map1 {...}

(2) Teste se um key1 chave valor existe em um map1:

val1, isPresent = map1[key1]which gives: val or zero-value, true or false

(3) A exclusão de uma chave em um mapa:

delete(map1, key1)

Structs

Fazer:

type struct1 struct {field1 type1field2 type2

...

} ms := new(struct1)

Inicialização:

Page 403: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

ms := &struct1{10, 15.5, “Chris”}

Capitalizar a primeira letra do nome da estrutura para torná-lo visível do lado de fora da embalagem.Muitas vezes, é melhor para definir uma função de factory para a estrutura, e forçar o uso:

ms := Newstruct1{10, 15.5, “Chris”}func Newstruct1(n int, f float32, name string) *struct1 { return &struct1{n, f, name}}

Interfaces

(1) Como testar se um valor v implementa uma interface de Stringer:

if v, ok := v.(Stringer); ok {fmt.Printf(“implements String( ): %s\n”, v.String( ));}

(2) Um tipo de classificador:

func classifier(items ...interface{ }) { for i, x := range items { switch x.(type) { case bool: fmt.Printf(“param #%d is a bool\n”, i) case float64: fmt.Printf(“param #%d is a float64\n”, i) case int, int64: fmt.Printf(“param #%d is an int\n”, i) case nil: fmt.Printf(“param #%d is nil\n”, i) case string: fmt.Printf(“param #%d is a string\n”, i) default: fmt.Printf(“param #%d’s type is unknown\n”, i) } }}

Funções

Como usar recuperar para parar um panic terminando sequencial:

func protect(g func( )) { defer func( ) {

log.Println(“done”) / / Println executa normalmente, mesmo se houver um panic

if x := recover( ); x != nil {log.Printf(“run time panic: %v”, x)

} }( )

log.Println(“start”) g( )}

Arquivos

(1) Como abrir e ler um arquivo:

Page 404: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

file, err := os.Open(“input.dat”) if err!= nil {

fmt.Printf(“An error occurred on opening the inputfile\n” + “Does the file exist?\n” + “Have you got acces to it?\n”)return

} defer file.Close( )

Goeader := bufio.NewReader(file)for {

str, err := Goeader.ReadString(‘\n’) if err!= nil {

return / / error or EOF } fmt.Printf(“The input was: %s”, str)

}

(2) Como ler e escrever um arquivo com um tampão cortado:

func cat(f *file.File) { const NBUF = 512 var buf [NBUF]byte for { switch nr, er := f.Read(buf[:]); true { case nr < 0:

fmt.Fprintf(os.Stderr, “cat: error reading from %s: %s\n”,f.String( ), er.String( ))

os.Exit(1) case nr == 0: / / EOF return case nr > 0: if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {

fmt.Fprintf(os.Stderr, “cat: error writing from %s: %s\n”, f.String( ), ew.String( ))

} } }}

Goroutines e canais

Conselho de desempenho:

Uma regra de ouro, se você usar o paralelismo para ganhar eficiência sobre computação em série: a quantidade de trabalho realizado dentro goroutine tem que ser muito maior do que os custos associados à criação goroutines e envio de dados e para trás entre eles.

1 - Utilizando canais buffer para o desempenho:Um canal tamponada pode facilmente dobrar a sua produção, dependendo do contexto, o ganho de

desempenho pode ser 10x ou mais. Você pode ainda tentar otimizar ajustando o capacidade do canal.

2 - A limitação do número de itens em um canal e embalá-los em arrays:Canais se tornar um gargalo se você passar um monte de itens individuais através deles. Você pode

contornar isso através da embalagem blocos de dados em arrays e, em seguida, a descompactação do outro lado. Isso pode ser um ganho de velocidade de um fator de 10x.

Page 405: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

Fazer: ch := make(chan type, buf)

(1) Como laço sobre um ch canal com um para-range:

for v := range ch { / / Faz algo com v}

(2) Como testar se um ch canal está fechado:

/ / Lê o canal até que se feche ou erro de condiçãofor { if input, open := <-ch; !open { break } fmt.Printf(“%s “, input)}Ou uso (1), onde a detecção é automática.

(3) Como usar um canal para que o programa principal esperar até o goroutine completa?(Padrão Semaphore):

ch := make(chan int) / Aloca um canal./ / Comece algo em um goroutine, quando ele completa, o sinal no canal.go func( ) { / / DoSomething ch <- 1 / / Envia um sinal, valor não importa.} ( )doSomethingElseForAWhile ( )<-Ch / / Espera goroutine terminar; descartar valor enviado.

Se a rotina deve bloquear para sempre, omitir ch <- 1 a partir da função lambda.

(4) Canal padrão de fábrica: a função é uma fábrica de canal e inicia uma função lambda como goroutine preencher o canal

func pump( ) chan int { ch := make(chan int) go func( ) {

for i := 0; ; i++ {ch <- i

} }( ) return ch

}

(5) Simples padrão timeout:

timeout := make(chan bool, 1)go func( ) { time.Sleep(1e9) / / um segundo timeout <- true

} ( )

select {case <-ch: / / A leitura de ch ocorreucase <-ch: / / A leitura de ch expeirou

Page 406: Linguagem de Programação Go Google Apostila Livro Curso.docx

CURSO GRATUITO

}

(6) Como usar um dentro e fora de canal em vez de bloqueio:

func Worker(in, out chan *Task) { for { t := <-in process(t) out <- t }}