Linguagem de Programação Go Google Apostila Livro Curso
Linguagem de Programação Go Google Apostila Livro Curso
Linguagem de Programação Go Google Apostila Livro Curso
org/
LINGUAGEM GO
SUBSTITUINDO C++ JAVA E MONO (.NET LINUX) NO SOFTERWARE LIVRE
MINHA PRIMEIRA LINGUAGEM DE PROGRAMAO LGICA, TCNICAS, ALGORITMOS PARA WEB E APLICATIVOS
APRENDENDO A PROGRAMAR
VISITE UMA IGREJA EVANGELICA
Go a Linguagem do Google
Durante muito tempo procurei livros e apostilas em Portugus sobre linguagem de programao Go, muitas pessoas procuram apreender Go, grande parte do material do site oficial bom, mas, no muito explicativo (para ler, so quase termos juridicos), ento resolvi traduzir livros gratuitos ou com licenas 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, no em Portugus.). necessario de uma permio por escrito para publicar uma verso ou derivado, os direitos de cpia (e Impresso) pertencem ao autores dos textos originais, por isso minha traduo annima . Grande parte do conteudo foi retirado do livro THE WAY TO GO de IVO BALBAERT, muitos tpicos foram suprimidos ou resumidos, este livro se encontra oficialmente e disponivel gratuitamente mais no opensource em (https:/ /archive.org/details/TheWayToGo). Espero que os autores venham a se interessar em publicar seus livros em Portuguesl. No use este manual para fins comerciais, serve apenas como meio didatico. O foco dessa publicao ser um manual para o ensino inicial e intermedirio em aplicativos e redes, independente de plataforma (Linux ou Windows) incentivando a produo de programas de cdigos aberto, j que Go uma linguagem bastante facil (mesmo nivel que python) e tambem de cdigos aberto. Professores e alunos participem de uma comunidade de software livre maneira mais facil e rpida de aprender a programar. Os cdigoss livres disponiveis nos sites oficiais ou no sourceforge (onde tudo open sorce) para Windows, Mac e Linux podem ser usados sob a devida Licena, 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 compilao para plataforma alvo ou usando MinGW. Esse material traz varios conceitos introdutrios necessario para programao, como Algoritmo e lgica. 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 segurana e velocidade). Exponho agora dois pensamentos que no esto implementados neste momento, mas que deveria ter uma soluo 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 cdigos do opensource LiteIDE (IDE especifico para Go). Outra questo que a estrutura dessa linguagem deve ser usada para reconstruo de uma linguagem de programao C#, (que de dominio publico) que muito usado no Windows e linux (Vala).
SITE OFICIAL: http://golang.org/ GO IDEAL PARA USO E COMO PRIMEIRA LINGUAGEM DE PROGRAMAO 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 PADO E COMPLETA SEM DEPENDENCIAS CIRCULARES DOCUMENTAO ACOMPANHA O INSTALADOR EXECUO COMPARADA C/C++ COMPILAO RPIDA SIMILAR AO C IDIOMA LEVE COM APENAS 25 PALAVRAS-CHAVE MENOS ESCRITURAO
Rede Social Acadmica http:/ /www.ebah.com.br http:/ /passeidireto.com Principais sites Software e Linux: www.softwarelivre.gov.br http:/ /softwarelivre.org www.vivaolinux.com.br http:/ /br-linux.org http:/ /www.linuxmagazine.com.br http:/ /olinux.uol.com.br http:/ /www.linuxdescomplicado.com.br http:/ /www.linuxbrasil.org.br
A sabedoria convencional nos diz que precisamos nos precaver contra ladres e malfeitores.Quando eles eventualmente conseguem seus intentos, precisamos acionar o Estado, atravs de instituies como Polcia e Justia, para que possamos fazer valer nossos direitos. A utilizao de softwares livres, ou seja, programas de internet com cdigos abertos, que podem ser copiados e modificados por qualquer pessoa, pode ser uma opo para evitar problemas de espionagem como os que foram denunciados recentemente. A avaliao do diretor-presidente do Servio Federal de Processamento de Dados (Serpro), Marcos Mazoni. O mundo do software livre uma belssima resposta a tudo isso que est acontecendo no mundo hoje. Se ns trabalhamos com cdigos fechados, que no nos permitem saber o que esto fazendo, muito mais propcio a uma deciso desse fornecedor se vai nos espionar ou no. No mundo do software livre, a deciso passa para ns, muda de lado, passa para o mundo do usurio explica. Mazoni lembra que a implementao do software livre em plataformas de governos sempre teve como foco aumentar a segurana dos dados dos pases. Para debater essas e outras questes, o Serpro promoveu a sexta edio do Congresso Internacional Software Livre e Governo Eletrnico (Consegui), em Braslia. O tema deste ano Portabilidade, Colaborao e Integrao. So temas muito atuais: estamos trabalhando com a lgica de que o mundo da tecnologia vai ter que suportar mobilidade, rede social, grandes quantidades de informaes, disse Mazoni. O evento ter 50 oficinas e 150 palestras, com a participao de representantes de diversos pases, entre agentes pblicos, movimentos sociais, hackativistas, pesquisadores e estudantes para debater
Linux
Linux um termo utilizado para se referir sistemas operacionais que utilizem o ncleo Linux. O ncleo Linux foi desenvolvido pelo programador finlands Linus Torvalds, inspirado no sistema Minix. O seu cdigo fonte est disponvel sob a licena GPL (verso 2) para que qualquer pessoa o possa utilizar, estudar, modificar e distribuir livremente de acordo com os termos da licena. Inicialmente desenvolvido e utilizado por grupos de entusiastas em computadores pessoais, os sistemas operacionais com ncleo Linux passaram a ter a colaborao 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 estveis e cada vez mais versteis de softwares livres para escritrio (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 proprietrios, e interfaces grficas cada vez mais amigveis como o KDE e o GNOME, o ncleo Linux, conhecido por sua estabilidade e robustez, tem gradualmente cado no domnio popular, encontrando -se cada vez mais presente nos computadores de uso pessoal atuais. Mas j h muito que o Linux destaca -se como o ncleo preferido em servidores de grandes porte, encontrando-se quase sempre presente nos mainframes de grandes empresas e at mesmo no computador mais rpido do mundo, o Tianhe -2, chins (lista mundial TOP500 dos supercomputadores).
GNU General Public License GNU General Public License (Licena Pblica Geral), GNU GPL ou simplesmente GPL, a designao
1. 2. 3. 4.
O ncleo (ou Kernel) Linux foi, originalmente, escrito por Linus Torvalds do Departamento de Cincia da Computao da Universidade de Helsinki, Finlndia, com a ajuda de vrios programadores voluntrios atravs da Usenet (uma espcie de sistema de listas de discusso existente desde os primrdios da
Usando Aplicativos Windows no Linux Wine (acrnimo recursivo para WINE Is Not an Emulator, isto , WINE No um Emulador, em traduo livre) um emulador para sistemas operativos UNIX que tem como objetivo a implementao da API do Microsoft Windows. Desta forma, em teoria, o Wine permite a execuo de aplicaes desenvolvidas para ambiente Windows nativamente noutros sistemas operativos. Wine, traduzido literalmente do ingls para o portugus, significa vinho, o que levou escolha de uma taa de vinho como logotipo do Wine. Por reimplementar as bibliotecas do Windows o Wine no um emulador, no fazendo qualquer emulao para executar software para Windows. A implementao da API do Windows faz -se atravs da utilizao de APIs e funes especficas de ambientes UNIX, sendo apenas necessria a implementao adicional de um carregador de aplicativos no formato PE, capaz de os converter para o formato ELF em run time. O WINE atua, ento, algo como um "tradutor": toda vez que ocorre uma chamada para a funo desenha Cubo que estava implementada no Directx.dll por exemplo, o Wine traduz est chamada para uma de suas prprias bibliotecas em que algum escreveu uma funo 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 funes que o Wine no sabe como interpretar, isto , chamam bibliotecas ou funes muito novas que os desenvolvedores do Wine ainda no implementaram. No entanto, o Wine permite a utilizao de bibliotecas nativas, apesar de, dado o fato de ser uma aplicao em user -mode num sistema operativo UNIX, nem todas funcionarem. Por exemplo, a utilizao do Directx da Microsoft uma impossibilidade tcnica (e legal). O Wine ainda disponibiliza a sua prpria biblioteca (Winelib) por forma a que o cdigo -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 cdigo fonte. No entanto, os programas compilados com Winelib precisam de ser executados sempre no Wine e, em particular, sempre na mesma verso. O nome Wine era inicialmente um acrnimo de Windows Emulator.1 Seu significado mais tarde deslocado para o Acrnimo 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 tambm um dos alfas mais longos de todos. Levou cerca de 10 anos desde o incio de seu desenvolvimento em 1993, por Bob Amstadt e Eric Youngdale, at a verso 1.0, lanada em junho de 2008. O projeto est atualmente na verso 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 verso 8), Microsoft Internet Explorer, mGOC, uTorrent, Ares Galaxy, Shareaza, Firefox (verso do Windows) e Winamp. O projeto tambm 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 smbolo
Tux - smbolo do software foi escolhido pelo seu criador (Linus Torvalds), que um dia estava no zoolgico e foi surpreendido pela mordida de um pinguim. Fato curioso e discutido at hoje. Em 1996, muitos integrantes da lista de discusso "Linux -Kernel" estavam discutindo sobre a criao de um logotipo ou de um mascote que representasse o Linux. Muitas das sugestes eram pardias 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 discusso. Depois disso, vrias tentativas foram feitas numa espcie de concurso para que a imagem de um pinguim servisse aos propsitos do Linux, at que algum 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 expresso de satisfeito, como se tivesse acabado de comer uma poro de peixes. Torvalds tambm no achava atraente a ideia de algo agressivo, mas sim a ideia de um pinguim simptico, do tipo em que as crianas perguntam "mame, posso ter um desses tambm?". Ainda, Torvalds tambm frisou que trabalhando dessa forma, as pessoas poderiam criar vrias modificaes desse pinguim. Isso realmente acontece. Quando questionado sobre o porqu de pinguins, Linus Torvalds respondeu que no havia uma razo em especial, mas os achava engraados e at citou que foi bicado por um "pinguim assassino" na Austrlia e ficou impressionado como a bicada de um animal aparentemente to inofensivo podia ser to dolorosa.
Ubuntu
Ubuntu um sistema operacional de cdigo aberto, construdo a partir do ncleo Linux, baseado no Debian. patrocinado pela Canonical Ltda. O Ubuntu diferencia-se do Debian por ter verses lanadas semestralmente, por disponibilizar suporte tcnico nos 9 meses seguintes ao lanamento de cada verso (as verses 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 concepo. A proposta do Ubuntu oferecer um sistema que qualquer pessoa possa utilizar sem dificuldades, independentemente de nacionalidade, nvel de conhecimento ou limitaes fsicas. O sistema deve ser constitudo principalmente por software livre. Deve tambm ser isento de qualquer taxa. Os fs do Ubuntu so conhecidos como "ubuntistas", "ubunteiros" ou "ubunteros". Atualmente, a pgina do Ubuntu no Distrowatch segunda mais acessada (com base anual). Em 8 de julho de 2005, Mark Shuttleworth e a Canonical Ltda. anunciaram a criao da Fundao Ubuntu e providenciaram um suporte inicial de US$ 10 milhes. A estreitolidade da fundao garantir apoio e desenvolvimento a todas as verses 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 ns somos". Esse nome busca passar a ideologia do projeto, baseada nas liberdades do software livre e no trabalho comunitrio de desenvolvimento. O sistema muito comumente chamado "Ubuntu Linux", porm, oficialmente a Canonical, desenvolvedora do sistema, usa apenas o nome "Ubuntu", uma vez que o sistema ao ser portado para outros ncleos livres para alm do Linux recebe outros nomes (por exemplo, o Ubuntu
Novas verses do Ubuntu so lanadas duas vezes ao ano, uma no ms de Abril e outra no ms 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 instalao padro Acessibilidade e internacionalizao, permitindo a utilizao do sistema pelo maior nmero de pessoas possvel. A partir da verso 5.04, a codificao de caracteres padro o UTF -8 (permitindo a utilizao de caracteres no utilizados no alfabeto latino). O projeto visa tambm a oferecer suporte tcnico nos idiomas de seus usurios Alm das ferramentas de sistema padro e outros aplicativos menores, o Ubuntu oferecido com diversos programas pr-instalados que atendem s funcionalidades bsicas, entre os quais esto a sute de aplicativos Libre Office e o navegador de internet Firefox. Programas para visualizar contedos multimdia, clientes de e-mail e jogos simples completam o sistema bsico O Ubuntu possui uma forte ligao com a comunidade Debian, contribuindo direto ou indiretamente com qualquer modificao nos cdigos fonte, ao invs de apenas anunciar essas mudanas em uma data posterior. Muitos programadores do Ubuntu mantm pacotes chave do prprio Debian Todas as verses do Ubuntu so disponibilizadas sem custo algum. O visual padro at a verso 5.10 e na verso 9.10 caracteriza -se pela utilizao de tons castanhos; entre as verses 6.06 (Dapper Drake) e 9.04 (Jaunty Jackalope), no entanto, passou -se a usar um padro de cores mais prximo do laranja. A verso 10.04 passou a adotar um padro de cores mais diversificado A gesto de instalao 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 instalao permanente. O Live CD utilizado por muitos usurios a fim de testar a compatibilidade de hardware antes de instalar o sistema Qualquer verso at a 12.04 ocupa apenas um CD (at 700 MB); a partir da verso 12.10, ser necessrio um DVD ou um pen drive, pelo fato da nova verso ultrapassar o limite de 700 MB. A atualizao e instalao de mais programas poder ser realizada via Internet, num processo fcil e em ambiente grfico. Para quem pretende experimentar o Ubuntu sem o instalar no disco rgido, 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 tambm. Estes modos so mais lentos e destinam -se essencialmente a proporcionar um primeiro contato com o Ubuntu, seus programas includos e saber quais programas podem ser eventualmente instalados; alm de ser til para manuteno de hardware. A partir da verso 6.06, este disco pode ser utilizado para se instalar definitivamente no computador.
Requisitos de sistema A verso desktop do Ubuntu atualmente suporta as arquiteturas Intel x86 e AMD64. Suporte no -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, lanado em 1 de abril de 2010). Uma GPU suportada requerida para habilitar efeitos visuais. Requisitos mnimos Processor (x86) com o conjunto de instrues i686 Memria RAM Disco rgido (espao livre) Resoluo do monitor Servidor 300 MHz 128 MiB 1 GB 640480 Desktop 700 MHz 512 MiB 5 GB 1024768
Uma nova verso do Ubuntu lanada semestralmente, e cada lanamento tem um nome de cdigo e um nmero de verso. O nmero de verso baseado no ano e no ms de lanamento. Por exemplo o Ubuntu 4.10 foi lanado em outubro de 2004, na data: ms 10, ano 2004. Abaixo est uma lista dos lanamentos anteriores e os lanamentos planejados. A partir da verso 13.04 em diante, o suporte em
Kubuntu, verso do Ubuntu que utiliza o ambiente grfico KDE Xubuntu, Ubuntu para computadores menos potentes, utilizando o ambiente grfico Xfce Gobuntu, Ubuntu somente com software livre, utilizando o ambiente grfico GNOME Fluxbuntu, Ubuntu somente com software livre, utilizando o ambiente grfico FluxBox Ubuntu Studio, para edio e criao de contedo multimdia Edubuntu, Ubuntu desenvolvido para o uso em escolas Lubuntu, distro com interface grfica LXDE voltada para computadores atrs e/ou pouco potentes
Dentre as verses no-oficiais (derivadas) destacam-se:
O pr-requisito bsico para a colaborao em um projeto de software opensource entender como o software funciona, e depois entender como funciona o projeto. Alguns projetos disponibilizam roadmaps (uma espcie de passo-a-passo) que mostram para onde esto caminhando. Outros tambm fornecem guias sobre como colaborar. Os guias so quase sempre criados em torno do que mais necessrio no projeto. Para colaborar em um projeto voc no precisa exclusivamente programar. H diversas formas de colaborao: Documentao Uma coisa certa sobre os programadores: Eles adoram programar! E por isso, normalmente tendem a deixar de lado tarefas necessrias para o projeto, como a criao da documentao dos softwares. Por documentao, entendemos os manuais de uso, guias de instalao, tutoriais e FAQ's. Tudo que possa oferecer um suporte impessoal para o usurio, fazendo com que este s procurar o suporte pessoal (Listas de E-mail, Canais de GOC, Fruns de Discusso) depois de ler o manual. Em um projeto opensource, qualquer pessoa que conhea o software pode contribuir escrevendo a
Nascimento e teoria da computao Antes da dcada de 1920, computador era um termo associado a pessoas que realizavam clculos, geralmente liderados por fsicos. Milhares de computadores eram empregados em projetos no comrcio, governo e stios de pesquisa. Aps a dcada de 1920, a expresso mquina computacional comeou a ser usada para referir-se a qualquer mquina que realize o trabalho de um profissional, especialmente aquelas de acordo com os mtodos da Tese de Church-Turing. O termo mquina computacional acabou perdendo espao para o termo reduzido computador no estreitol da dcada de 1940, com as mquinas digitais cada vez mais difundidas. Alan Turing, conhecido como pai da cincia da computao, inventou a Mquina de Turing, que posteriormente evoluiu para o computador moderno. Computao pode ser definida como a soluo de um problema ou, formalmente, o clculo de uma funo, atravs de um algoritmo. A teoria da computao, um subcampo da cincia da computao e
computador chamado de unidade central de processamento. Tudo o que um computador faz supervisionado pela CPU. Memria. Esta uma rea de armazenamento rpida usada para guardar dados. Ela tem de ser rpida porque se conecta diretamente ao microprocessador. H vrios tipos especficos de memria em um computador: Memria RAM - usada para armazenar temporariamente as informaes que o computador est manipulando no momento; Memria apenas de leitura (ROM) - um tipo permanente de armazenamento de memria usado pelo computador para dados importantes que no mudam; Basic input/output system (BIOS) - um tipo de ROM que usado pelo computador para estabelecer a comunicao bsica quando o computador iniciado; Cache - a rea de armazenamento dos dados frequentemente usados em memria RAM, extremamente rpida, conectada diretamente CPU; Memria virtual - espao no disco rgido usado para armazenar temporariamente dados na memria RAM, chaveando-os quando necessrio; Memria RAM - usada para armazenar temporariamente as informaes que o computador est manipulando no momento; Memria apenas de leitura (ROM) - um tipo permanente de armazenamento de memria usado pelo computador para dados importantes que no mudam; Basic input/output system (BIOS) - um tipo de ROM que usado pelo computador para estabelecer a comunicao bsica quando o computador iniciado; Cache - a rea de armazenamento dos dados frequentemente usados em memria RAM, extremamente rpida, conectada diretamente CPU; Memria virtual - espao no disco rgido usado para armazenar temporariamente dados na memria RAM, chaveando-os quando necessrio; Placa-me - placa de circuito principal qual todos os outros componentes internos se conectam. A CPU e memria esto em geral na placa-me. Outros sistemas podem ser encontrados diretamente na placa-me ou conectados a ela atravs de uma conexo secundria. Por exemplo, uma placa de som pode estar presente na placa-me ou a ela ser conectada atravs do barramento PCI. Fonte de alimentao - um transformador eltrico regula a eletricidade usada pelo computador. Disco rgido - um depsito permanente e de grande capacidade, que guarda informaes como programas e documentos. Sistema operacional - software bsico que permite ao usurio interfacear com o computador. Controlador IDE (Integrated Drive Electronics) - interface primria com o disco rgido, CD -ROM e drive de disquete. Barramento PCI (Peripheral Component Interconnect) - maneira mais comum de conectar componentes adicionais ao computador, o PCI usa uma srie de slots na placa-me nos quais as placas PCI se conectam. SCSI (Small Computer System Interface) - pronuncia-se "sczi" e um mtodo de adicionar dispositivos extras ao computador, como discos rgidos ou scanners. AGP (Accelerated Graphics Port) - uma conexo rpida usada pela placa grfica para fazer a interface com o computador. Placa de som - usada pelo computador para gravar e reproduzir udio, convertendo som analgico
Conexes: entrada/sada Independentemente do quo potentes os componentes do seu computador so, voc precisa de uma maneira de interagir com eles. Esta interao chamada entrada/sada (I/O). Os tipos mais comuns de I/O nos PCs so: Monitor - o monitor um dispositivo primrio para exibir as informaes do computador; Teclado - o teclado um dispositivo primrio para inserir informaes no computador; Mouse - o mouse um dispositivo primrio para navegar e interagir com o computador; Armazenamento removvel - os dispositivos de armazenamento removvel permitem adicionar novas informaes ao seu computador facilmente, alm de salvar as informaes que voc quer transportar para um local diferente. CD-ROM. O CD-ROM (compact disc, read-only memory) uma forma popular de distribuio de software comercial, e acabou transformando-se em mdia padro de armazenamento de dados. Muitos sistemas agora oferecem CD-R (gravvel) e CD-RW (regravvel), os quais tambm permitem a gravao. Memria flash. Baseada em um tipo de ROM chamada EEPROM (electrically erasable programmable read-only memory, ou memria apenas de leitura programvel e apagvel eletricamente), a memria Flash fornece armazenamento rpido e permanente. Os cartes CompactFlash, SmartMedia e PCMCIA so tipos de memria Flash. DVD-ROM. O DVD-ROM (digital versatile disc, read-only memory) semelhante ao CD-ROM, mas capaz de guardar muito mais informaes. Por sua capacidade de armazenamento, est substituindo o CD-ROM na preferncia dos usurios para back -up, compartilhamento de arquivos, e gravao de dados. Conexes: portas
Paralela. Esta porta geralmente usada para conectar uma impressora. Atualmente, as portas paralelas j no so mais a interface padro das impressoras e dos computadores. Elas foram substitudas pela conexo USB, que permite transferncia de dados mais rpida. Serial. Esta porta geralmente usada para conectar um modem externo. Tambm est em desuso. Nos sistemas atuais, a porta serial tambm foi substituda pela USB. USB (Universal Serial Bus). Este barramento rapidamente se tornou a conexo externa mais popular porque as portas USB oferecem versatilidade e so muito fceis de usar. FirewGoe (IEEE 1394) - O FirewGoe um mtodo popular de conectar dispositivos de vdeo digital, como filmadoras e cmeras digitais, ao seu computador.
Conexes: Internet/rede
Modem. Este o mtodo padro de conexo com a Internet discada. A maioria dos computadores
atuais j no vem com modem. Em seu lugar, est instalada uma placa de rede 10/100, que permite conexo 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 escritrio. A placa permite acessar a internet, via rede, e outros computadores que fazem parte da mesma rede. Modem a cabo. Dispositivo que permite conexo Internet usando a rede de cabos da TV a cabo. Esse tipo de conexo atinge velocidade de at 10 Mbps. Modem DSL (Digital Subscriber Line). Esta uma conexo de alta velocidade que trabalha em uma linha telefnica padro. Usa a estrutura das operadoras de telefonia, e a mais usada no Brasil atualmente. Modem VDSL (Very high bit-rate DSL). Verso mais nova do DSL, o modem VDSL requer que sua linha telefnica tenha cabos de fibra tica.
A Otimizao de cdigo a estratgia de examinar o cdigo intermedirio, produzido durante a fase de gerao de cdigo com objetivo de produzir, atravs de algumas tcnicas, um cdigo que execute com bastante eficincia. O nome otimizado deve sempre ser encarado com cuidado, pois no se pode criar um programa que leia um programa P e gere um programa P equivalente sendo melhor possvel segundo o critrio adotado. Vrias tcnicas e vrias tarefas se renem sob o nome de Optimizao. Estas tcnicas consistem em detectar padres dentro do cdigo produzido e substitu -los por cdigos mais eficientes. Entre as tcnicas usadas esto a substituio de expresses que podem ser avaliadas durante o tempo de
A fase de gerao de cdigo estreitol a ltima fase da compilao. A gerao de um bom cdigo objeto difcil devido aos detalhes particulares das mquinas para os quais o cdigo gerado. Contudo, uma fase importante, pois uma boa gerao de cdigo pode ser, por exemplo, duas vezes mais rpida que um algoritmo de gerao de cdigo ineficiente. Nem todas as tcnicas de optimizao so independentes da arquitetura da mquina-alvo. Optimizaes dependentes da mquina necessitam de informaes tais como os limites e os recursos especiais da mquina -alvo a fim de produzir um cdigo mais compacto e eficiente. O cdigo produzido pelo compilador deve se aproveitar dos recursos especiais de cada mquina alvo. O cdigo objeto pode ser uma sequncia de instrues absolutas de mquina, uma sequncia de instrues de mquina relocveis, 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 elaborao 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 usurio e possivelmente fazer algum reparo para que o processamento possa continuar. Os erros podem ser classificados em erros lxicos, erros sintticos, erros no independentes de contexto (semnticos), erros de execuo e erros de limite. Os erros lxicos ocorrem quando um token identificado no pertence a gramtica da linguagem fonte. Os erros sintticos ocorrem quando alguma estrutura de frase no est de acordo com a gramtica, como por exemplo parnteses sem correspondncia. Os erros no independentes de contexto em geral so associados a no declarao de objetos como variveis e erros de tipos. Alguns compiladores encerram o processo de traduo logo ao encontrar o primeiro erro do programa-fonte. Esta uma poltica de fcil implementao. Compiladores mais sofisticados, porm, detectam o maior nmero possvel de erros visando diminuir o nmero de compilaes. A recuperao de erros em analisadores sintticos top -down mais fcil de implementar do que em analisadores bottom -up. O problema que diferente de um analisador top -down, este ltimo no sabe quais smbolos so esperados na entrada, somente os que j foram processados. Pode -se usar neste caso tcnicas como, por exemplo, a tcnica de panic -mode que procura em tabelas sintticas em busca de smbolos vlidos na entrada. Nesta tcnica se descartam smbolos da entrada at que um delimitador (como um ponto e vrgula, por exemplo) seja encontrado. O analisador apaga as entradas da pilha at que encontre uma entrada que permita que o processo de anlise 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 criao dos algoritmos do que na sua prpria implementao, pois quando bem projetados no 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 padro a que leva seu prprio nome: Linguagem Java. Uma grande vantagem da plataforma a de no estar presa a um nico sistema operacional ou hardware, pois seus programas rodam atravs de uma mquina virtual que pode ser emulada em qualquer sistema que suporte linguagem C++. O universo Java um vasto conjunto de tecnologias, composto por trs plataformas principais que foram criadas para segmentos especficos de aplicaes: Java SE (Java Platform, Standard Edition). a base da plataforma. Inclui o ambiente de execuo e as bibliotecas comuns.
SITE OFICIAL: http://golang.org/ Java EE (Java Platform, Enterprise Edition). A edio voltada para o desenvolvimento de aplicaes
corporativas e para internet.
Java ME (Java Platform, Micro Edition). A edio para o desenvolvimento de aplicaes para dispositivos
mveis e embarcados. Alm disso, pode-se destacar outras duas plataformas Java mais especficas: Java Card. Voltada para dispositivos embarcados com limitaes de processamento e armazenamento, como smart cards e o Java Ring. JavaFX. Plataforma para desenvolvimento de aplicaes multimdia em desktop/web (JavaFX Script) e dispositivos mveis (JavaFX Mobile). A plataforma Java constituda de um grande nmero de tecnologias, cada uma prov uma poro distinta de todo o ambiente de desenvolvimento e execuo de softwares. Os usurios estreitos, tipicamente, interagem com a mquina virtual Java (Java Virtual Machine, ou JVM) e um conjunto padro de bibliotecas de classe. Existe um grande nmero de maneiras de se utilizar uma aplicao Java, incluindo applets embutidas em pginas web, aplicativos de uso geral em desktops, aplicativos em aparelhos celulares e em servidores de aplicaes para Internet (Apache Tomcat, Glassfish, JBoss etc.). Os desenvolvedores de aplicaes em Java utilizam um conjunto de ferramentas de desenvolvimento, o JDK. O corao 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 execuo, o bytecode para instrues nativas do processador. Isto permite que uma mesma aplicao seja executada em qualquer plataforma computacional que possua uma implementao da mquina virtual. Desde a verso 1.2 da JRE, a implementao da Sun da JVM inclui um compilador just -in-time (JIT). Com este compilador todo o bytecode de um programa transformado em instrues nativas e carregado na mquina virtual em uma s operao, permitindo um ganho de desempenho muito grande em comparao com a implementao anterior, onde as instrues em bytecode eram interpretadas uma por vez. O compilador JIT pode ser projetado de acordo com a plataforma ou hardware de destino, e o cdigo que ele gera pode ser otimizado com base na observao de padres de comportamento dos programas. Desde a primeira verso, este ambiente de execuo vem equipado com gesto automtica de memria, realizada por um algoritmo coletor de lixo garbage collector, que liberta o programador das tarefas de alocao e libertao de memria, fonte de muitos erros de programao. A plataforma Java no a primeira plataforma baseada em uma mquina virtual, mas de longe a mais conhecida e a que alcanou maior sucesso. Anteriormente esta tecnologia era utilizada na criao de emuladores para auxlio ao projeto de hardware ou de sistemas operacionais. A plataforma Java foi desenhada para ser implementada inteiramente em software, enquanto permitindo a sua migrao de maneira fcil para plataformas de hardware de todos os tipos. O sucesso da plataforma Java e o seu conceito write once, run anywhere levaram a outros esforos similares. O mais notvel destes esforos a plataforma .NET, da Microsoft, que utilizou muitos dos conceitos e inovaes 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 referncia a linguagem de programao 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 dinmica, inspirada em linguagens como Python, Ruby e Smalltalk. Tambm existem implementaes 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 ingls: dotNet) uma iniciativa da empresa Microsoft, que visa uma plataforma nica para desenvolvimento e execuo de sistemas e aplicaes. Todo e qualquer cdigo 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 cdigo para um sistema ou dispositivo especfico, 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 cdigo compilado, recuperar o cdigo original. Isto no uma ideia agradvel para as empresas que sobrevivem da venda de softwares produzidos nesta plataforma.
RACIOCNIO As crianas aprendem facilmente como adicionar e subtrair valores, depois a dividir e multiplicar equaes simples. Suas dificuldades comeam no momento em que elas se deparam com problemas e necessitam identificar quais operaes traro solues para os mesmos. Programas so formulaes concretas de algoritmos abstratos, baseados em representaes e estruturas especficas de dados.
Aprendendo a Estudar Programao. Nos dias que correm, no saber trabalhar com computadores considerada iliteracia (analfabetismo) e o custo por no saber utilizar um computador pode ser caro. Quando usamos computadores, podemos fazer muitas coisas. Uma criana pode usar a Internet para passar uma mensagem, um estudante pode usar uma planilha eletrnica para calcular uma mdia ou quantos pontos precisa para ser aprovado em cada matria, 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 to grande que, se voc procurar bem, certamente vai encontrar algum programa que faa algo bem prximo do que voc deseja. O problema que, s vezes, queremos fazer algo especfico: queremos um programa de computador que faa algo que servir de forma nica a ns ou a nossa empresa. Nesse caso, em vez de comprar um programa pronto temos que desenvolver o nosso prprio programa. Para isso necessrio dominar uma nova forma de manipular o computador: a programao. Nosso motivo pode ser um negcio, um trabalho escolar, um hobby ou mera curiosidade. Hoje em dia, programar um computador pode ser feito de vrias formas. Voc pode, por exemplo, modificar levemente o comportamento de aplicaes por meio de macros, como permitido em programas como Microsoft Word. Voc pode fazer ainda modificaes mais srias por meio de linguagens embutidas, como pode ser feito tambm nos programas do Microsoft Office ou at mesmo em jogos de computador como Neverwinter Nights. Voc pode tambm pegar um programa j existente de cdigo aberto, ou software livre e modific-lo. Ou voc pode comear do incio e programar praticamente tudo, certamente com ajuda de bibliotecas prontas que fazem parte do trabalho. Para programar voc tem muitas opes: pacotes que podem ser estendidos com macros ou linguagens embutidas, ambientes de programao point -and-click, linguagens mais fceis de aprender e linguagens mais difceis, mas que apresentam grande poder ou caractersticas apropriadas para grandes sistemas. Em todo caso, o esprito por trs de tudo o mesmo: programar dar ordens para o computador, mostrar como ele deve reagir ao usurio e como ele deve processar os dados disponveis. Praticamente no h limite do que voc pode fazer com um computador. Computadores ajudam pessoas a falar, controlam aparelhos e levaram o homem Lua de vrias maneiras. Mesmo as coisas mais difceis, como simular um sentimento ou inteligncia, so estudadas com afinco em todo mundo. Alguns problemas so muito grandes e exigem a construo de computadores enormes. Outros so to simples que podemos resolver em computadores simples, que esto dentro de equipamentos. Hoje difcil imaginar um domnio da atividade humana onde a utilizao de computadores no seja desejvel. Assim sendo o domnio da programao substancialmente ditado pela imaginao e criatividade. Podemos dizer que a grande vantagem de saber programar a possibilidade de criar o que quiser, quando quiser. No s para o PC, mas celulares, PDAs, entre outros. Claro que exige um pouco de esforo, porm para muitos esse esforo na verdade um desafio cuja a recompensa ver sua ideia transformada em realidade. Quando se pretende estudar uma linguagem, no se pode estar espera que lendo determinado livro ou frequentando determinado curso ficaremos a sab-la perfeitamente. A verdade que no 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 auxlio ao estudo e no 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 atravs de um livro ou manual. 2 - Entender as diferenas desta linguagem para outras que j saibam - Isto muito importante! 3 - Fazer algo que vai realmente torn-lo um bom programador dessa linguagem: Ler cdigo j
preciso ter em ateno estes passos que so fundamentais. Assim, se no souber o que determinada funo, sempre pode Go ao manual e procurar. No se prenda ao "marrano" do livro porque isso no o leva a nada. Este padro eficaz porque, para um iniciante, possvel aprender -se uma linguagem em pouco mais de 5 ou 6 meses. Para um programador experiente basta apenas uma a duas semanas para cessar a aprendizagem de uma nova linguagem. Aps a passagem por essa linguagem, inscreva-se numa das centenas de listas existentes na internet e aperfeioe os seus conhecimentos ajudando outros usurios a criar programas open source. Ver que se sentir feliz por ter chegado to longe! necessrio ter em mente que se seguir estas regras aprender a ser um bom programador.
1. Faa uma leitura de todo o problema at o estreitol, a fim de formar a primeira impresso. A seguir, releia o problema e faa anotaes sobre os pontos principais. 2. Verifique se o problema foi bem entendido. Questione, se preciso, ao autor da especificao sobre suas dvidas. Releia o problema quantas vezes for preciso para tentar entend -lo. 3. Extraia do problema todas as suas sadas. 4. Extraia do problema todas as suas entradas. 5. Identifique qual o processamento principal. 6. Verifique se ser necessrio algum valor intermedirio que auxilie a transformao das entradas em sadas. Esta etapa pode parecer obscura no incio, mas com certeza no desenrolar do algoritmo, estes valores aparecero 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 criao. Conselho: S tente conseguir o timo, depois de realizar o bom.
1 Todo programador tem que saber lgica de programao, no existe programador sem lgica. 2 Ningum quer te ajudar, a no 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 no pior que ningum, e ningum melhor que voc. Todos ns somos inteligentes, ningum burro. Apenas algumas pessoas so mais estudadas que voc. 5 Voc no tem que gostar de ler, mais tambm no pode odiar. Voc pode no gostar de ler um livro com tema amoroso, ou dramtico, mas um livro sobre programao (Que o que voc estuda) voc tem que gostar. Se no gostar porque est tentando aprender programar?
Classificao
at que certa condio seja satisfeita e ele terminado, que um mtodo comum em programao funcional. Algoritmos iterativos usam estruturas de repetio tais como laos, 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 construo. os axiomas usados na computao e o componente de controle determina a maneira como a deduo aplicada aos axiomas. Tal conceito base para a programao lgica.
Lgico - um algoritmo pode ser visto como uma deduo lgica controlada. O componente lgico expressa Serial ou paralelo - algoritmos so geralmente assumidos por serem executados instruo a instruo
individualmente, como uma lista de execuo, o que constitui um algoritmo serial. Tal conceito base para a programao 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 instruo ao mesmo tempo. Tais algoritmos dividem os problemas em subproblemas e o delegam a quantos processadores estiverem disponveis, agrupando no estreitol o resultado dos subproblemas em um resultado estreitol ao algoritmo. Tal conceito base para a programao paralela. De forma geral, algoritmos iterativos so paralelizveis; por outro lado existem algoritmos que no so paralelizveis, chamados ento problemas inerentemente seriais. exata a cada passo enquanto algoritmos no-determinsticos resolvem o problema ao deduzir os melhores passos atravs de estimativas sob forma de heursticas.
Determinstico ou no-determinstico - algoritmos determinsticos resolvem o problema com uma deciso Exato ou aproximado - enquanto alguns algoritmos encontram uma resposta exata, algoritmos de
aproximao procuram uma resposta prxima a verdadeira soluo, seja atravs de estratgia determinstica ou aleatria. Possuem aplicaes prticas sobretudo para problemas muito complexos, do qual uma resposta correta invivel devido sua complexidade computacional. Classificao por paradigma
Pode-se classificar algoritmos pela metodologia ou paradigma de seu desenvolvimento, tais como:
Diviso e conquista - algoritmos de diviso e conquista reduzem repetidamente o problema em subproblemas, geralmente de forma recursiva, at que o subproblema pequeno o suficiente para ser resolvido. Um exemplo prtico o algoritmo de ordenao merge sort. Uma variante dessa metodologia o decremento e conquista, que resolve um subproblema e utiliza a soluo para resolver um problema maior.
Programao dinmica - pode-se utilizar a programao dinmica para evitar o reclculo de soluo j resolvidas anteriormente. Algoritmo ganancioso - um algoritmo ganancioso similar programao dinmica, mas difere na medida em que as solues dos subproblemas no precisam ser conhecidas a cada passo, uma escolha gananciosa pode ser feita a cada momento com o que at ento parece ser mais adequado. Programao linear Reduo - a reduo resolve o problema ao transform-lo em outro problema. chamado tambm transformao e conquista. Busca e enumerao - vrios problemas podem ser modelados atravs de grafos. Um algoritmo de explorao de grafo pode ser usado para caminhar pela estrutura e retornam informaes teis para a resoluo do problema. Esta categoria inclui algoritmos de busca e backtracking. Paradigma heurstico e probabilstico - algoritmos probabilsticos realizam escolhas aleatoriamente. Algoritmos genticos tentam encontrar a soluo atravs de ciclos de mutaes evolucionrias entre geraes de passos, tendendo para a soluo exata do problema. Algoritmos heursticos encontram uma soluo aproximada para o problema. Classificao por campo de estudo Cada campo da cincia possui seus prprios problemas e respectivos algoritmos adequados para resolv-los. Exemplos clssicos so algoritmos de busca, de ordenao, de anlise numrica, de teoria de grafos, de manipulao de cadeias de texto, de geometria computacional, de anlise combinatria, de aprendizagem de mquina, de criptografia, de compresso de dados e de interpretao de texto. Classificao por complexidade Alguns algoritmos so executados em tempo linear, de acordo com a entrada, enquanto outros so executados em tempo exponencial ou at mesmo nunca terminam de serem executados. Alguns problemas tem mltiplos algoritmos enquanto outros no possuem algoritmos para resoluo. Podemos enquadrar os problemas em trs grandes grupos: Os que no tm soluo e portanto no h nada a fazer, que so classificados como problemas indecidveis (ou impossveis de serem solucionados). Os que tm soluo algortmica e podemos resolv -los formalmente passo a passo, codificando os algoritmos para sua resoluo. Um terceiro grupo que no pertencem aos dois anteriores. Dentre eles podemos ter: Aqueles em que a soluo algortmica tm complexidade NP -Completa; Aqueles que o Ser Humano capaz de resolver; Aqueles que os Seres Vivos so capazes de resolver. Ex: Jogar Xadrez, Jogar Futebol, Reconhecer Faces, Fazer Tradues, Procurar Comida, Reconhecer Letras, entre outros. Definio de problema difcil de explicar precisamente o que um problema, mas podemos explicar como sendo uma questo que se prope para ser resolvida. Note que resolver um problema no necessariamente significa em se ter um mtodo para resolv -lo. Antes mesmo de se tentar buscar a soluo de um problema, deve -se responder as seguintes perguntas: Quais so os dados (informaes)? Quais so as solues possveis? O que caracteriza uma soluo satisfatria? Tambm pode-se pensar que problema algo difcil de resolver, uma dvida, uma questo, enigma ou mistrio. Problema melhor "entendido" nas diferentes reas do conhecimento, por exemplo: Problema dos canibais e missionrios; Problema do caixeiro viajante; Problema das pontes de Knigsberg; Problema do carteGoo chins
1. 2. 3.
Tabuleiro de xadrez mutilado; Na Teoria dos problemas um problema pode ser representado em linguagem matemtica da seguinte forma: P = (I, B, C) P: O problema apresentado; B: O conjunto de dados do problema, conjunto no vazio, que deve representar a informao apropriada do problema. Alguns elementos podem permanecer iguais e outros em constante dinmica. necessrio documentar no s o estado inicial do problema mas tambm todos seus estados de mudanas. I: O conjunto de operaes e transformaes, tambm conjunto no vazio, que podem ocorrer durante o processo da resoluo do problema desde a sua fase inicial, as possveis respostas. C: Condio, uma relao binria, que deve satisfazer o problema. Esta relao caracteriza uma soluo satisfatria, ela associa a cada elemento do conjunto de dados a soluo nica desejada. Mais precisamente o conjunto soluo do problema. Caracterizao de um problema Uma pessoa que enfrenta um problema para satisfazer certos objetivos e no conhece que aes deve tomar para conseguir resolv-lo. Ento ao se resolver um problema identificamos os seguintes componentes: Um objetivo para ser alcanado, um conjunto de aes pr -pensadas para resolver tal problema e a situao inicial do tal problema. Exemplo: Um Puzzle Existe um tabuleiro de 4x4 casas e 15 peas somente. O problema que temos que fazer com que as peas espalhadas no quadrado formem uma configurao previamente definida. Existe uma regra para isso, o movimento somente ocorre uma pea por vez e somente para casas adjacentes. Neste caso o conjunto de dados do problema poderia ser descrito pela configurao das peas no tabuleiro, as operaes de busca da soluo como movimentos das peas de acordo com as regras, e a configurao estreitol a soluo do problema. Um problema de diagnstico mdico pode ser modelado da mesma maneira, seja: O problema "P" o diagnstico. O conjunto "B" da dados do problema so dados que o mdico obteve de exames com seu paciente. O conjunto "C" da soluo o conjunto de todas as doenas possveis. Neste caso, a busca de uma soluo encontrar um par (d,k), tal que d B e k C. Em casos como o diagnstico mdico estamos buscando uma funo que resolva o problema, essa funo denominada funo problema. Um outro exemplo, o problema da raiz de polinmio. A soluo do problema da busca das razes de um polinmio com coeficientes reais consiste em associar a cada conjunto de coeficientes de um polinmio particular p(x) de grau n, n nmeros complexos cn de modo a satisfazer a condio de que o valor de p(x) fazendo x = c para todo n seja nulo. A funo problema A funo problema, se existir, pode ser encontrada de diversas formas: Enumerao exaustiva: Enumerando todos os pares que ligam dados do problema ao conjunto soluo. Evidentemente, este modo de definir uma funo, s se aplica no caso que o conjunto de dados finito. Exemplo: Seja uma agenda de telefones. Ela pode ser considerada como a funo que associa a cada nome de pessoa seu telefone. Declarativamente: Definindo propriedades que definem a soluo do problema. Exemplo 1:
Pode-se reconhecer que, neste caso, a soluo no nica: todas as funes que sejam iguais dentro
subconjunto em que o problema definido so vlidas e necessrio fazer uma aproximao, neste caso costuma-se usar tcnicas de Inteligncia artificial como Rede neural, Usam -se os exemplos para treinar a rede e obtm-se valores estimados da soluo para os outros valores usando a propriedade de generalizao das redes. Exemplo: Costuma-se empregar redes neurais com aprendizado supervisionado. Usam -se os exemplos para treinar a rede e obtm-se valores estimados da soluo para os outros valores usando a propriedade de generalizao das redes
Para Aprender uma Linguagem Muitos anos se passaram desde os primrdios da histria da computao, mas apesar de j termos vivido vrios paradigmas de programao, existe uma base de conhecimento que no mudou e no mudar nunca a Lgica de Programao. Fao uma associao direto da Lgica de Programao com o Raciocnio Matemtico, onde o importante a interpretao de um problema e a utilizao correta de uma frmula, e no a sintaxe pr definida da mesma. O saber da Lgica est no praticar. No existem frmulas em Informtica, o que existe o aperfeioamento de nossa forma de pensar e raciocinar sobre um problema, podendo extrair do mesmo uma soluo eficiente e eficaz, sob um determinado ngulo de viso. Assim, verificamos que preciso aprender a pensar sobre os problemas, extraindo deles o mximo de informaes. A soluo que criamos para um determinado problema necessita ser exteriorizada e expressa numa linguagem publicamente conhecida. Assim, utilizamos a lgica de programao para desenvolver nossas solues e os algoritmos para apresentar essas solues ao mundo. Vrios livros de Algoritmos e Estruturas de Dados. Todos ensinam como representamos estruturas de controle e atribuies, ou como declaramos variveis, mas nenhum deles que eu tenha lido at o momento , orientou o aluno na forma de pensar. Precisamos mais do que frmulas, precisamos aprender a pensar. Apresentaremos como desenvolver algoritmos de solues 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 estratgia foi bem sucedida aps testar o programa num computador. Bons programadores tem poucas surpresas quando testam seus programas, fazendo normalmente umas poucas correes para que o programa funcione de maneira adequada. Programadores iniciantes criam uma estratgia (algoritmo) muitas vezes ineficiente no raro ouvirmos de iniciantes a frase Nunca conseguirei fazer um programa .... Certamente, no conseguir mesmo, caso no tenha uma estratgia definida. Imagine uma tarefa muito simples, como por exemplo fritar um ovo. Caso voc no soubesse operar
Soluo: Caractersticas Ideais Executveis Curtos Executveis Rpidos Portveis Simplicidade Manipulao de Bits 0- No Importa 1- Desejvel Classe No Importa Fundamental Desejvel Desejvel Necessrio 2- Necessrio Valor 0 3 1 1 2 3- Fundamental
A Programao Estruturada pode ser entendida como uma forma de programar que visa facilitar a escrita, entendimento, validao e manuteno de programas. Para a arte de programar consiste na arte de organizar e dominar a complexidade. A Programao Estruturada procurar reduzir o nvel de complexidade atravs de trs nveis: a) desenvolvimento do programa em diferentes fases por reestreitomento sucessivo (desenvolvimento top-down); b) decomposio do programa total em mdulos funcionais, organizados de preferncia num sistema hierrquico; c) uso de um nmero limitado de estruturas bsicas de fluxo de controle dentro de cada mdulo. DESENVOLVIMENTO TOP-DOWN Na Programao Estruturada, ao desenvolvermos um algoritmo, temos como objeto um produto estreitol o programa. Todavia, para termos esta transio, passamos por vrias fases, no sentido cima para baixo, onde cada fase documentada e principalmente obtida por reestreitomento da fase anterior, at chegarmos a um nvel de detalhamento que permita implementar o algoritmo diretamente na linguagem de programao. MODULARIZAO A soluo estreitol de um problema obtida atravs de solues de subproblemas, o que permite dividir o programa em mdulos com subjunes claramente delimitadas, que podem, inclusive, ser implementados separadamente, por diversos programadores de uma equipe.
comum um processo ter que esperar at que uma condio se torne verdadeira. Para essa espera ser "eficiente", o processo deve esperar no estado bloqueado (sem competir pela UCP). Dois tipos de bloqueio so considerados bsicos:
1.
2. Programas clssicos
Bloquear at que um recurso se torne disponvel; Bloquear at que chegue um sinal de outro processo.
Esta seo apresenta 4 problemas clssicos da programao concorrente, todos resolvidos atravs do uso de semforos 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 posies. 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 relao 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 programao desse sistema com buffer de 5 posies e supondo que as mensagens sejam nmeros inteiros. Jantar dos Filsofos Este problema ilustra as situaes de deadlock e de postergao indefinida que podem ocorrer em sistemas nos quais processos adquirem e liberam recursos continuamente. Existem N filsofos 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 situao para 5 filsofos. Como a massa muito escorregadia, ela requer dois garfos para ser comida. Na mesa existem N garfos, um entre cada dois filsofos, e os nicos garfos que um filsofo pode usar so os dois que lhe correspondem (o da sua esquerda e o da sua direita). O problema consiste em simular o comportamento
1
PROGRAMANDO EM REDE COM A LINGUAGEM GO PROGRAMANDO EM REDE NA LINGUAGEM GOLANG Este captulo aborda as principais caractersticas arquitetnicas de systems distribudos. 1.1 Introduo Voc no pode construir um sistema sem uma ideia do que voc quer construir e se voc no conhecer o ambiente em que ele vai trabalhar. Programas grficos so diferentes de programas de processamento em lote, programas de jogos so diferentes de programas de negcios e programas distribudos so diferentes de programas independentes. Cada um tem as suas abordagens, seus padres comuns, o problemas que normalmente surgem e as solues que so frequentemente utilizados. Este captulo aborda os aspectos arquitetnicos Highl evel de sistemas distribudos. H muitas maneiras de olhar para tais sistemas, e muitos deles so tratados. Camadas de protocolo Sistemas distribudos so difceis. Existem vrios computadores envolvidos, que tm de ser ligados de alguma forma. Os programas tm de ser escrito para ser executado em cada computador no sistema e todos eles tm de cooperar para comear uma tarefa feita distribuda. A forma mais comum de lidar com a complexidade dividi -la em partes menores e mais simples. Estas peas tm a sua prpria estrutura, mas eles tambm tm definido meios de comunicao com outras partes relacionadas. Em sistemas distribudos, as partes so chamados protocolo camadas e tm funes claramente definidos. Eles formam uma pilha, com cada camada de comunicao com a camada superior e a camada abaixo. A comunicao entre as camadas definida por protocolos. Rede de comunicaes requer protocolos de comunicao para cobrir aplicao de alto nvel, todo o caminho para o fio de comunicao e a complexidade tratadas por encapsulao em camadas de protocolo. ISO OSI Protocolo Embora nunca foi devidamente implementado, o protocolo OSI (Open Systems Interconnect) foi uma grande influncia na forma de falar e influenciar design de sistemas distribudos. comumente dado na figura a seguir:
responsvel por endtoend recuperao de erros e controle de fluxo Camada de sesso estabelece, gerencia e termina conexes entre aplicaes. Camada de apresentao fornece independncia de diferenas na representao de dados (por exemplo, criptografia) Camada de aplicao suporta os processos de aplicao e do usurio estreitol Protocolo TCP / IP
Camada de rede fornece tecnologias de comutao e roteamento Camada de transporte fornece transferncia transparente de dados entre sistemas estreitos e
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 tm sido imensamente bem sucedido. Este um pilha muito mais simples:
Alguns protocolos alternativos Embora quase parece que, os protocolos TCP / IP no so os nicos na existncia e no longo prazo, no pode mesmo ser o mais bem sucedido. Existem muitos protocolos ocupando nichos significativos, tais como:
Networking Uma rede um sistema de comunicaes para conectar sistemas estreitos chamados hosts. Os mecanismos de conexo pode ser de fio de cobre, eternet, fibra ptica ou wireless, mas isso no nos interessa aqui. Uma rede de rea local (LAN) conecta computadores que so juntas, normalmente pertencente a uma casa, pequena organizao ou parte de uma organizao maior. A Wide Area Network (WAN) conecta computadores em uma rea fsica maior, como entre as cidades. Existem outros tipos como bem, como MANs (Metropolitan Area Network), PANs (Personal Network) e entre outras. Uma internet uma conexo de duas ou mais redes distintas, tipicamente LANs ou WANs. Uma intranet uma internet com todas as redes pertencente a uma nica organizao. Existem diferenas significativas entre uma internet e intranet. Normalmente uma intranet estaro sob uma nica administrao controle, que Ir impor um nico conjunto de polticas coerentes. Uma internet, por outro lado no estar sob o controle de uma nica corpo, e os controles exercidos sobre diferentes partes no pode mesmo ser compatvel. Um exemplo trivial de tais diferenas que uma intranet, muitas vezes, ser restringido a computadores por um pequeno nmero de fornecedores que executam um verso padronizada de um determinado sistema operacional. Por outro lado, uma internet, muitas vezes, tm um smorgasborg de diferente computadores e sistemas operacionais. As tcnicas deste livro ser aplicvel a internets. Eles tambm sero vlidos para intranets, mas l voc tambm vai encontrar sistemas especializados, no portteis. E depois h a "me" 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 genrico para uma entidade utilizada para ligar duas ou mais redes. Um repetidor opera para as cpias de nvel fsico a informao de uma sub -rede para outra. Uma ponte opera no nvel da camada de enlace de dados e cpias de quadros entre as redes. A router opera no nvel de rede, e no s se move informaes entre redes, mas tambm decide sobre a rota. Packet encapsulamento A comunicao 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 prxima, e depois, eventualmente, atravs da rede. Cada camada tem informaes administrativas que ele tem de manter sobre sua prpria camada. Ele faz isso atravs da adio de informaes de cabealho do pacote que recebe da camada superior, como o pacote passa para baixo. No receber lado, estes cabealhos so 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 atravs de Ethernet. Isso se parece com:
O pacote transmitido over ethernet, claro, a um fundo. Modelos de conexo Para que dois computadores se comuniquem, eles devem estabelecer um caminho pelo qual eles podem enviar pelo menos uma mensagem em uma sesso. Existem dois modelos principais para isso:
Sistemas dirigidos por eventos de nvel superior supor que esta subjacente e, em seguida, o evento despachados para um objeto ButtonPress. Isto tambm pode ser feito de passagem de mensagens mensagem recebida atravs da rede parcialmente decodificados apropriado. Chamada de procedimento remoto
decodificao foi feito pelo sistema apropriado, como um manipulador distribudas sistemas, em que uma e enviados para um manipulador
Em qualquer sistema, h uma transferncia de informao 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 informao 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 variaes. O cdigo pode ser estaticamente ligado de modo que a transferncia de controle de uma parte do cdigo executvel do programa para outra parte. Devido ao aumento do uso de rotinas de biblioteca, tornou-se comum ter tais cdigo em bibliotecas de vnculo dinmico (DLL), onde as transferncias de controle para uma pea independente de cdigo. A mecnica no so to 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 captulo posterior.
H uma estranheza histrica chamada de "leve chamada de procedimento remoto" inventado pela Microsoft como a transio de 16 bits para Aplicativos de 32 bits. A aplicao de 16 bits pode precisar transferir dados para um aplicativo de 32 bits na mesma mquina. Isso fez com que ele leve, pois no havia rede! Mas tinha muitas das outras questes de sistemas de RPC em representaes de dados e converso. Modelos de computao distribuda Na maior nvel, podemos considerar a equivalncia ou a no equivalncia dos componentes de um sistema de distribuio. A maioria ocorrncia comum uma assimtrica um: um cliente envia pedidos para um servidor, e servidor responde. Este um cliente servidor sistema. Se ambos os componentes so equivalentes, ambos capazes de iniciar e responder a mensagens,
E um terceiro ponto de vista Servidor Distribudo A sistemas cliente servidor no precisa ser simples. O modelo bsico o cliente nico, 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 so possveis clientes simultneos.
H tambm nico cliente, vrios servidores que ocorre frequentemente quando um servidor precisa agir como um cliente para outro servidores, como um servidor de lgica de negcios a obteno de informaes a partir de um servidor de banco de dados. Com vrios servidores. E, claro, no poderia haver vrios clientes Componente de Distribuio Uma maneira simples, mas eficaz, de decompor muitas aplicaes consider -los como composta de trs partes: Componente Apresentao A lgica da aplicao Acesso a dados O componente de apresentao responsvel pela interao com o usurio, tanto a apresentao de dados e coleta de entrada. Pode ser um interface grfica moderna, com botes, listas, menus, etc, ou uma interface mais velho estilo de linha de comando, fazendo perguntas e obtendo respostas. Os detalhes no so importantes a este nvel. A lgica do aplicativo responsvel por interprete as respostas dos usurios, para a aplicao de regras de negcio, para consultas de preparao e gesto respostas do componente thir. O componente de acesso a dados responsvel pelos dados stroing e recuperar. Este ser muitas vezes por meio de uma base de dados, mas no necessariamente. Gartner Classificao Com base nesta decomposio trplice de applicaitons, o Gartner considera a forma como os componentes podem ser distribudos em um cliente system servidor. Eles vieram com cinco modelos:
Os telefones mveis modernos so bons exemplos disso: devido memria limitada podem armazenar uma pequena parte de um banco de dados localmente para que podem responder rapidamente. Banco de dados para que os dados adicionais. No entanto, se os dados necessria, que no realizada no local, em seguida, uma solicitao 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 usurio, o mapas "prximas" so baixado tambm em um pequeno banco de dados no navegador. Quando o usurio move o mapa um pouco, os bits extras necessrio j est na loja local para resposta rpida. Exemplo: Rede de Atendimento do Arquivo Classificao Gartner 2 permite que clientes remotos acesso a um sistema de arquivos compartilhado
H muitos exemplos de sistemas scuh: NFS, as aes da Microsoft, DCE, etc Exemplo: Web
Exemplo: emulao de terminal Um exemplo de classificao Gartner 4 emulao 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 ilustrao do romance de classificao Gartner 5. Ele atua como um wrapper em torno de um sistema clssico, como uma linha de comando interface. Ele cria uma interface X Window em torno deste, de modo que o usurio interage com uma interface grfica, e GUI, por sua vez interage com o interface de linha de comando.
Exemplo: X Window System O prprio Sistema X Window um exemplo de classificao Gartner 5. Uma aplicao faz chamadas GUI, tais como, Mas estes DrawLine no so tratados diretamente, mas em vez passou a um servidor X Window para renderizao. Isso separa a visualizao do aplicativo de janelas e a vista de exibio de janelas.
Trs modelos de camada claro, se voc tem duas camadas, ento voc pode ter trs, quatro, ou mais. Alguns dos trs possibilidades camadas so mostrados neste Diagrama:
O moderno Web um bom exemplo da direita destes. O mtodo composto por um banco de dados, muitas vezes funcionando armazenados procedimentos para realizar parte da lgica de banco de dados. A camada intermediria um servidor HTTP como o Apache executando scripts PHP (ou Ruby ou Pginas Rails, ou JSP, etc.) Isso vai gerir parte da lgica e ter dados como pginas HTML armazenados localmente. O frontend um navegador para exibir as pginas, sob o controlo de alguns Javascript. No HTML 5, a interface tambm pode ter um banco de dados local.
Largo vs estreito A rotulagem de componentes em comum "largo" ou "estreito". Componentes de gordura ocupam muita memria e fazer o processamento complexo. Estreito componentes, por outro lado, fazer pouco de ambos. No parece haver qualquer componentes de tamanho "normal", s largo ou estreito! Gordura ou magreza um conceito relativo. Browsers so frequentemente laelled to estreito, porque "tudo que eles fazem pginas web diplay". Firefox em minha caixa de Linux leva quase 1/2 de um gigabyte de memria, que eu no considero to pequeno em tudo! Modelo Middleware Middleware teh "cola" que liga os componentes de um sistema distribudo. O modelo de middleware
Middleware
Componentes de middleware incluem Os servios de rede incluem coisas como TCP / IP A camada de middleware s independente do aplicativo / w usando os servios de rede Exemplos de middleware so: DCE, RPC, Corba Middleware pode desempenhar apenas uma funo (como a RPC) ou muitos (como DCE)
Exemplos Middleware
Exemplos de middleware incluem Servios primitivos, como emuladores de terminais, transferncia de arquivos, e-mail Servios bsicos como RPC Servios integrados, como DCE, Rede O / S Servios de objetos distribudos, como CORBA, OLE / ActiveX Objeto servios mveis, como RMI, Jini World Wide Web
Funes de middleware
dados
As funes de middleware incluem Iniciao de processos em diferentes computadores Gerenciamento de sesso Os servios de diretrio para permitir que os clientes a localizar servidores acesso remoto aos Controle de concorrncia para permitir que servidores para lidar com vrios clientes Segurana e integridade Monitorao Resciso de processos local e remoto
Continuo de Processamento O modelo Gartner baseado em uma quebra de uma aplicao em componentes de apresentao, lgica de aplicao e dados manuseamento. A mais estreito quebra de gro
Pontos de falha Aplicaes distribudas 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 Conteno de rede poderia causar timeouts Pode haver conflitos de endereos de rede Os elementos da rede, como roteadores poderia deixar Erros de transmisso pode perder mensagens As verses cliente e servidor pode ser incompatvel 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 corrompido Os pedidos tm de ser concebidos com estas possveis falhas em mente. Qualquer ao realizada por um componente deve ser recupervel se a falha ocorre em alguma outra parte do sistema. Tcnicas como transaes e erro contnua necessidade verificando a ser utilizada para evitar os erros. Fatores de Aceitao
Transparncia acesso
SITE OFICIAL: http://golang.org/ Transparncia de localizao Transparncia migrao Transparncia replicao Transparncia de concorrncia Transparncia escalabilidade Transparncia desempenho Transparncia falha
Oito falcias da computao distribuda Sun Microsystems foi uma empresa que realizou a maior parte do trabalho inicial em sistemas distribudos, e ainda teve um mantra "O rede o computador. "Com base em sua experincia ao longo de muitos anos um nmero de cientistas da Sun veio com a seguinte lista de falcias comumente assumidas: 1. A rede de confiana. 2. A latncia zero. 3. Largura de banda infinita. 4. A rede segura. 5. Topologia no muda. 6. Existe um administrador. 7. Custo de transporte zero. 8. A rede homognea. Muitas delas impactam diretamente sobre a programao da rede. Com a premissa de que a rede de confiana de modo a que uma chamada de procedimento remota Ir comportar -se da mesma forma como uma chamada local. Por exemplo, a concepo da maior parte dos sistemas de chamadas de procedimento remotas baseia zero banda latncia e infinita tambm levar a suposies sobre o tempo de durao de uma chamada RPC sendo o mesmo como um local de As falcias ligar, ao passo que so grandezas de ordem mais lentas. O reconhecimento dessas falcias levou o modelo de Java RMI (Remote Method Invocation) a exigir que cada chamada RPC para potencialmente lanar um. Isto forou os programadores a, pelo menos, reconhecer a possibilidade de erro de rede e para lembr-los de que eles RemoteException no poderia esperar que as mesmas velocidades como chamadas locais.
PROTOCOLOS
3.2 A pilha TCP / IP O modelo OSI foi criado atravs de um processo em que o comit padro foi criado e, em seguida, implementados. Algumas partes do o padro OSI so obscuras, algumas peas no podem ser facilmente implementadas, algumas partes no foram implementadas. O protocolo TCP / IP foi criado atravs de um projeto DARPA de longa durao. Isso funcionou por implementao seguido por RFCs (Request For Comment). TCP / IP o principal protocolo de rede Unix. TCP / IP = Transmission Control Protocol / Internet Protocolo. A pilha TCP / IP mais curto do que o OSI one:
O TCP um protocolo orientado a conexo, o UDP (User Datagram Protocol) um protocolo sem conexo. Datagramas IP A camada IP oferece um sistema de entrega sem conexo e no confivel. Ele considera cada datagrama independentemente dos outros. Qualquer associao entre datagramas devem ser fornecidos pelas camadas mais altas. A camada IP fornece uma soma de verificao que inclui o seu prprio cabealho. O cabealho inclui os endereos de origem e de destino. A camada IP lida com encaminhamento atravs de uma Internet. Ele tambm responsvel pela quebra de grandes datagramas em partes menores para transmisso e reunidas na outra extremidade. UDP UDP tambm sem conexo e no confivel. O que ele adiciona ao IP uma soma de verificao para o contedo dos nmeros de datagramas e porturias. Estes so utilizados para dar a / modelo cliente servidor ver mais tarde. TCP TCP fornece a lgica para dar um protocolo orientado a conexo confivel acima de IP. Ele fornece um circuito virtual que dois processos podem utilizar para se comunicar. Ele tambm usa nmeros de porta para identificar os servios em um host. Adresses Internet Para utilizar um servio voc deve ser capaz de encontr -lo. A Internet usa um esquema de endereos para dispositivos como computadores, de modo que eles podem ser localizados. Este esquema de endereamento foi originalmente concebido, quando havia apenas um punhado de computadores conectados e muito generosamente permitiu at 2 ^ 32 endereos, usando um inteiro no assinado de 32 bits. Estes so os chamados endereos IPv4. Em recente anos, o nmero de dispositivos conectados (ou pelo menos diretamente endereveis) ameaou ultrapassar esse nmero, e assim "qualquer dia agora "vamos mudar para o IPv6, que vai permitir que at 2 ^ 128 endereos, usando um inteiro de 128 bits sem sinal. A passagem mais provvel de ser forado por pases emergentes, como o mundo desenvolvido j tomou quase todo o pool de endereos IPv4. Endereos IPv4 O endereo um nmero inteiro de 32 bits que d o endereo IP. Isso resolve a uma placa de interface de rede em um nico dispositivo. O endereo normalmente composto por quatro bytes em decimal com um ponto '.' entre eles, como em "127.0.0.1" ou "66.102.11.104". O endereo de IP de qualquer dispositivo geralmente composta de duas partes: o endereo da rede em que o dispositivo reside, e o endereo do dispositivo nessa rede. Era uma vez, a diviso entre o
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 { IP IP Port int }
A funo 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 endereo IP, seguido pelo porto nmero aps um ":"., como "www.google.com:80" ou '127.0.0.1:22 "se o endereo um endereo IPv6, que j tem dois pontos em, ento a parte de host deve ser colocado entre colchetes, como "[:: 1]: 23". Outro caso especial usado frequentemente para servidores, onde o endereo do host zero, de modo que o endereo TCP realmente apenas o nome da porta, como em ": 80" para um servidor HTTP. TCP Sockets Quando voc sabe como chegar a um servio atravs da sua rede e porta IDs, o que ento? Se voc um cliente, voc precisa de uma API que permitir que voc se conectar a um servio e, em seguida, para enviar mensagens para esse servio e ler as respostas de volta do servio. 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 comunicao full duplex entre o cliente e servidor. Dois mtodos principais de interesse so 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 endereo TCP para um servio, ele "disca" o servio. Se bem sucedido, o mostrador retorna um para Tcpconn comunicao. O cliente e servidor trocam mensagens sobre este assunto. Normalmente, um cliente escreve um pedido para o servidor usando a funo func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) Onde laddr o endereo local, que geralmente definido como e RADDR o endereo remoto do servio, e a string um zero rede de "tcp4", "tcp6" ou "tcp", dependendo se voc quer uma conexo TCPv4, uma conexo TCPv6 ou no se importam. Um exemplo simples pode ser fornecido por um cliente para um servidor web (HTTP). Ns vamos lidar substancialmente mais detalhe com clientes HTTP e servidores em um captulo posterior, mas por agora ns vamos mant-lo simples. Uma das possveis mensagens que um cliente pode enviar a mensagem "Cabea". Esta consulta um servidor para obter informaes sobre o servidor e um documento no servidor. O servidor retorna as informaes, mas no retorna o prprio documento. O pedido enviado para consultar um servidor HTTP pode ser "HEAD / HTTP/1.0\r\n\r\n" Que pede informaes sobre o documento raiz e servidor. Uma resposta tpica poderia ser HTTP/1.0 200 OK ETag: "-9985996" Last-Modified: Thu, 25 Mar 2010 17:51:10 GMT Content-Length: 18074 Connection: close Date: Sat, 28 Aug 2010 00:43:48 GMT Server: lighttpd/1.4.23
O primeiro ponto a ser observado a quantidade quase excessivo de verificao de erro que est acontecendo. Isso normal para programas de rede: As oportunidades para o fracasso so 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 comunicao 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 verificaes so realizadas: 1. Pode haver erros de sintaxe no endereo especificado
return } } } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error( )) os.Exit(1) } }
Controlar conexes TCP Timeout O servidor pode querer tempo limite um cliente se ele no responder com suficiente rapidez que o IE no escrever um pedido para o servidor no tempo. Este deve ser um longo perodo (alguns minutos), pois o usurio 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 Um cliente pode querer ficar ligado a um servidor, mesmo que ele no tem nada para enviar. Pode
/* 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) } }
Escrever um servidor pode ser simplificado de modo semelhante utilizando a funo func Listen(net, laddr string) (l Listener, err os.Error) Que retorna um objeto implementar a interface Listene. Este interface tem um mtodo func (l Listener) Aceitar ( ) (c Conn, err os.Error) o que permitIr que um servidor a ser construdo. Usando isso, o servidor de eco multithreaded 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) } } func handleClient(conn net.Conn) {
soquetes primas e do tipo IPConn Esta seo abrange material avanado que a maioria dos programadores improvvel que precisa. Trata-se de raw sockets, que permitem a programador para construir seus prprios protocolos IP, ou usar diferentes protocolos TCP ou UDP TCP e UDP no so os nicos protocolos construdos acima da camada IP. O sitehttp:/ /www.iana.org/assignments/protocolnumbers lists, cerca de 140 deles (esta lista frequentemente disponveis em sistemas Unix no arquivo). TCP e UDP so apenas os nmeros 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 prprio pas. Mas d suporte mnimo: ele Ir se conectar exrcitos, e escrever e ler pacotes entre os hosts. No prximo captulo, vai olhar para projetar e implementar os seus prprios protocolos TCP acima; esta seo considera o mesmo tipo de problema, mas, ao Camada IP. Para manter as coisas simples, vamos usar quase o mais simples possvel 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 anfitrio responde. O formato :
O primeiro byte 8, de p para a mensagem de eco O segundo byte zero O terceiro e quarto bytes so uma soma de verificao em toda a mensagem Os quinto e sexto bytes so um Identificador arbitrria
SITE OFICIAL: http://golang.org/ Os stimo e oito bytes so um nmero de sequncia arbitrria O restante do pacote de dados de utilizador
O programa a seguir vai preparar uma conexo IP, envie uma solicitao 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 {
serializao de dados A comunicao entre um cliente e um servio requer a troca de dados. Este dados podem ser altamente estruturado, mas tem que ser serializado para o transporte. Este captulo olha para as noes bsicas de serializao e, em seguida, considera vrias tcnicas apoiadas Por GO APIs. Um cliente e servidor precisam trocar informaes atravs de mensagens. TCP e UDP fornecer os mecanismos de transporte para fazer isso. O dois processos tambm tem que ter um protocolo no lugar para que a troca de mensagens pode ocorrer de forma significativa. As mensagens so enviadas atravs da rede como uma sequncia de bytes, que no tem estrutura, exceto para um fluxo linear de bytes. Ns deve abranger as diversas possibilidades de mensagens e os protocolos que os definem no prximo captulo. Neste captulo, concentrar -se em um componente de mensagens os dados que so transferidos. Um programa normalmente construir estruturas complexas de dados para armazenar o estado atual programa. Em conversa com um cliente remoto ou servio, o programa ser a tentativa de transferir tais
registros / estruturas registros variantes array tamanho fixo ou varivel string tamanho fixo ou varivel mesas por exemplo, arrays de registros Estruturas no lineares, como Lista ligada circular rvore binria Objetos com referncias 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 sequncia de bytes. Assim, uma aplicao 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 operaes so conhecidas como mobilizar e unmarshalling respectivamente. Por exemplo, considere o envio da seguinte tabela de comprimento varivel de duas colunas de cadeias de comprimento varivel:
Isto poderia ser realizado por vrias maneiras. Por exemplo, suponhamos que sabido que os dados vo ser um nmero desconhecido de linhas numa tabela de duas colunas. Em seguida, uma forma empacotada pode ser 3 4 fred 10 programmer 6 liping 7 analyst 8 sureerat 7 manager / / 3 rows, 2 columns assumed / / 4 char string,col 1 / / 10 char string,col 2 / / 6 char string, col 1 / / 7 char string, col 2 / / 8 char string, col 1 / / 7 char string, col 2
Coisas de comprimento varivel pode, alternativamente, ter seu comprimento indicado pela terminao ls com um valor de "ilegal", como '\ 0' para strings: 3 fred\0 programmer\0 liping\0 analyst\0 sureerat\0 manager\0 Alternativamente, pode ser conhecido que os dados so de uma tabela fixa de 3 filas de duas colunas de cadeias de comprimento 8 e 10 respectivamente. Em seguida, uma serializao pode ser fred\0\0\0\0 programmer liping\0\0 analyst\0\0\0 sureerat manager\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 serializao de dados
acordo mtuo A seo anterior apresentou uma viso geral do problema de serializao de dados. Na prtica, os pormenores podem ser consideravelmente mais complexa. Por exemplo, considere a primeira possibilidade, mobilizar uma tabela para a corrente 3 4 fred 10 programmer 6 liping 7 analyst 8 sureerat 7 manager Muitas perguntas surgem. Por exemplo, quantas linhas so possveis para a mesa ou seja, o quo grande um nmero inteiro que precisamos para descrever o tamanho da linha? Se for 255 ou menos, ento um nico byte vai fazer, mas se for mais, ento pode ser necessrio um curto, inteiro ou longo. Um semelhante problema ocorre para o comprimento de cada string. Com os prprios personagens, para o qual o conjunto de caracteres que eles pertencem? Bit ASCII de 7? 16 bit Unicode? A questo de conjuntos de caracteres discutido em detalhe em um captulo posterior. A serializao acima opaco ou implcita. Se os dados codificado usando o formato acima, ento no h nada no serializado dados para dizer como deve ser unmarshalled. O lado unmarshalling tem que saber exatamente como os dados so serializados, a fim de desempacota -lo corretamente. Por exemplo, se o nmero de linhas empacotado como um nmero inteiro de oito bits, mas unmarshalled como um dezesseis bits nmero inteiro, ento 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 mtodo de serializao cedo conhecido XDR (representao 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 especificao preciso. Mesmo assim, XDR tipo insegura inerentemente como dados serializados no contm informaes de tipo. A correo de seu uso em ONC assegurada principalmente por compiladores de cdigo de gerao, tanto para triagem e unmarshalling. Go no contm suporte explcito para triagem ou unmarshalling dados serializados opacos. O pacote RPC em Go no usa XDR, mas usa a serializao "gob", descrito mais adiante neste captulo. dados autodescrevendo Dados auto descritivo carrega digitar informaes, juntamente com os dados. Por exemplo, os dados anteriores pode ter como codificado table uint8 3 uint 2 string uint8 4 [ ]byte fred string uint8 10 [ ]byte programmer string uint8 6 [ ]byte liping string uint8 7 [ ]byte analyst string uint8 8 [ ]byte sureerat string
Claro que, uma codificao real no seria normalmente to 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 possvel. (XML fornece um contraexemplo, embora.). No entanto, o princpio que o marshaller Ir gerar tais informaes digite os dados serializados. O unmarshaller vai saber as regras de gerao 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 indstria de telecomunicaes. ASN.1 um complexo padro, 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 codificao de certificados X.509, que so muito utilizadas em sistemas de autenticao. O apoio em Go baseado no que necessrio para ler e escrever certificados X.509. Duas funes 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 ns nos movemos para alm desta, as coisas ficam mais difceis. 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 mtodo de serializao ser capaz de lidar com certos tipos de dados e no lidar com alguns outros. Assim, a fim de determinar o adequao de qualquer serializao como ASN.1, voc tem que
Um INTEGER ASN.1 pode ser escrito para um int ou int64. Se o valor codificado no 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 sequncia 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 sequncia de ASN.1 ou SET pode ser gravado em um struct se cada um dos elementos na sequncia pode ser escrito para o elemento na estrutura correspondente.
Go coloca restries reais em ASN.1. Por exemplo, permite ASN.1 inteiros de qualquer tamanho, embora a aplicao Vai s permitIr at assinado inteiros de 64 bits. Por outro lado, Go distingue entre tipos assinados e no assinados, enquanto ASN.1 no. Assim, para exemplo, a transmisso de um valor de uint64 pode falhar se ele muito grande para int64, Na mesma linha, ASN.1 permite que vrios conjuntos de caracteres diferentes. Go s suporta PrintableString e IA5String (ASCII). ASN.1 no suporta caracteres Unicode (que requerem a extenso ASN.1 BMPString). O conjunto de caracteres Unicode bsico de Go no suportados, e se um aplicativo exige transporte de caracteres Unicode, ento uma codificao como UTF7 ser necessrio. Essas codificaes so discutidas em um captulo posterior sobre conjuntos de caracteres. Vimos que um valor como um inteiro pode ser facilmente empacotado e unmarshalled. Outros tipos bsicos como booleanos e reais podem ser tratados de forma semelhante. Strings que so compostos inteiramente de caracteres ASCII pode ser empacotado e unmarshalled.
Em geral, voc provavelmente vai querer empacotar e desempacotar estruturas. Para alm do caso especial de tempo, Go ter todo o prazer lidar com estruturas, mas no com ponteiros para estruturas. Operaes como criar ponteiros, ento voc tem que excluir a referncia a eles new antes de triagem / unmarshalling eles. V normalmente diferentes ponteiros para voc quando necessrio, mas no neste caso. Estes dois trabalhar para um tipo de T: / / using variables var t1 T t1 = ... mdata1, _ := asn1.Marshal(t) var newT1 T asn1.Unmarshal(&newT1, mdata1) / // using pointers var t2 = new(T) *t2 = ... mdata2, _ := asn1.Marshal(*t2) var newT2 = new(T) asn1.Unmarshal(newT2, mdata2) Qualquer combinao adequada de indicadores e variveis vai funcionar to bem. Os campos de uma estrutura devem ser todos exportvel, ou seja, os nomes de campo deve comear com uma letra maiscula. Go usa a refletir pacote para empacotar / desempacotar as estruturas, por isso deve ser capaz de examinar todos os campos. Este tipo no pode ser empacotado: type T struct { Field1 int field2 int / / not exportable } ASN.1 s lida com os tipos de dados. No considera os nomes dos campos de estrutura. Ento, o seguinte tipo de T1pode ser marshalled / unmarshalled em tipo T2como os campos correspondentes so os mesmos tipos: type T1 struct { F1 int
/* 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 }
codificao do Unicode carter de substituio U + FFFD. Valores da array e slice codificar como arrays JSON, s que [ ] byte codifica como uma sequncia codificada em base64. Valores struct codificar como objetos JSON. Cada campo de struct torna-se um membro do objeto. Por padro nome da chave do objeto o nome do campo struct convertida em minsculas. 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
Os valores booleanos codificar como booleanos JSON. Valores de ponto flutuante e inteiros codificar como nmeros de JSON. Valores String codificar como strings JSON, com cada sequncia UTF8 invlida substituda pela
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] 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 } 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 tcnica de serializao especfico para Go. Ele projetado para codificar Go tipos de dados especfica e no dispe atualmente de apoio ou por qualquer outro idioma. Ele suporta todos os tipos de dados Go, exceto para os canais, funes 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 anis, mas que vai melhorar com o tempo. Gob codifica digitar informaes em suas formas serializados. Isto muito mais extensa do que o tipo de informao em dizer um X.509 serializao, mas muito mais eficiente do que o tipo de informao contida em um documento XML. Digite as informaes est includo apenas uma vez por cada segmento de dados, mas inclui, por exemplo, os nomes dos campos struct. Esta incluso de informaes sobre o tipo faz Gob triagem e unmarshalling bastante robusto para mudanas ou diferenas entre o marshaller e unmarshaller. Por exemplo, uma estrutura struct T { a int b int } Pode ser empacotado e depois unmarshalled em uma estrutura diferente struct T { b int a int } Onde a ordem dos campos mudou. Ele tambm pode lidar com campos faltantes (os valores so ignorados) ou campos extras (os campos so 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 coero para que um int campo pode ser ampliado em um int64 , Mas no com incompatvel 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 parmetro e empacotamento ser eito para este fluxo de gravao. O codificador tem um mtodo Codificar Marshalls que o valor para o fluxo. Este mtodo pode ser chamado vrias vezes em vrias partes de dados. Digite as informaes para cada tipo de dados s escrito uma vez, no entanto. Voc usa um para desempacotar o fluxo de dados em srie. Isso leva um Decoder Leitor 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
/* 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 { 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
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)
Codificao de dados binrios como strings Era uma vez, transmtting dados de 8 bits era problemtico. Foi muitas vezes transmitida atravs de linhas seriais ruidosos e poderia facilmente tornar -se corrompido. Dados de 7 bits, por outro lado, pode ser transmitida de forma mais fivel porque o 8o bit pode ser usado como o dgito de verificao. Para exemplo, em um esquema de "paridade", o dgito de verificao seria definida como um ou zero para fazer um nmero par de 1s em um byte. Este permite a deteco de erros de um nico bit de cada byte. ASCII um conjunto de caracteres de 7 bits. Um nmero de esquemas foram desenvolvidos que so mais sofisticados do que simples paridade verificao, mas que envolvem a traduo de dados binrios 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 binrios transmitidos em respostas HTTP e solicitaes muitas vezes traduzido em uma forma ASCII. Isto torna mais fcil 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 vrios formatos binrios para texto, incluindo base64. Existem duas funes principais a serem usadas para a codificao e decodificao Base64: func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser func NewDecoder(enc *Encoding, r io.Reader) io.Reader Um programa simples, apenas para codificar e decodificar um conjunto de oito dgitos binrios /** * 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)
Protocolos de nvel 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 captulo analisa algumas das questes envolvidas nisso, e d um exemplo completo de um aplicao cliente servidor simples. Um cliente e servidor precisam trocar informaes atravs de mensagens. TCP e UDP fornecer os mecanismos de transporte para fazer isso. Os dois processos tambm 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 aplicao distribuda, especificando as mensagens, dados tipos de formatos de codificao, e assim por diante. Protocolo de Projeto H muitas possibilidades e questes a serem decididas na concepo de um protocolo. Algumas das questes incluem:
ser TCP ou UDP. para ser stateful vs aptrida? razovel 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 confivel ou no confivel? Confiana muitas vezes mais lento, mas ento voc no precisa se preocupar tanto com mensagens perdidas. So respostas necessrias? Se for necessria uma resposta, como voc lida com uma resposta perdida? Pode ser usado Tempos limite. O formato de dados que voc quer? Duas possibilidades comuns so MIME ou codificao byte. o seu fluxo de comunicao em rajadas ou estvel? Ethernet e a Internet so os melhores em trfego em rajadas. Fluxo constante necessrio para streams de vdeo e, particularmente, para a voz. Se necessrio, como voc administra Qualidade de Servio (QoS)? Existem vrios fluxos com a sincronizao necessria? Ser que os dados precisam ser sincronizados com alguma coisa? por exemplo, vdeo e voz. Voc est construindo um aplicativo independente ou uma biblioteca para ser usado por outras pessoas? Os padres de documentao necessria pode variar. O controle de verso 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 verso 2 Ir fazer pedidos que uma verso um servidor no entendem, enquanto que um servidor da verso 2 Ir enviar responde que um cliente da verso 1 no vai entender. Cada lado deve, idealmente, ser capaz de compreender as mensagens para a sua prpria verso e todos os anteriores. Deve ser capaz de escrever para respostas consultas de estilo antir em formato de
Ser que para ser transmitido ou ponto a ponto? Transmisso deve ser UDP, multicast local ou o MBONE mais experimental. Ponto a ponto poderia
A capacidade de falar formatos de verses anteriores podem ser perdidos se o protocolo muda muito. Neste caso, voc precisa ser capaz de garantir que nenhuma cpia da verso anterior ainda existem e que geralmente impossvel. Parte da configurao do protocolo deve envolver informaes sobre a verso. A Web A Web um bom exemplo de um sistema que confuso por diferentes verses. O protocolo tem sido atravs de trs verses, e a maioria dos servidores / navegadores agora usar a verso mais recente. A verso dada em cada pedido Mas o contedo das mensagens tem sido atravs de um grande nmero de verses:
presente se seu navegador tem um manipulador para Flash? Tratamento inconsistente de contedo do documento (por exemplo, alguns contedos de estilo Ir falhar alguns navegadores) Suporte diferente para Java Script (e verses diferentes de Java Script) Motores de tempo de execuo diferentes para Java Muitas pginas no se conformam com qualquer verses HTML (por exemplo, com erros de sintaxe) Message Format No ltimo captulo, discutimos algumas possibilidades para a representao de dados a serem enviados atravs do fio. Agora vamos olhar para um nvel acima, a as mensagens que podem conter tais dados.
Verses HTML 14 (todos diferentes), com a verso 5 no horizonte; etiquetas fora do padro reconhecido por diferentes navegadores; Documentos no HTML muitas vezes exigem manipuladores de contedo que pode ou no estar
O cliente e servidor Ir trocar mensagens com diferentes significados. Ex: Solicitao de login, Obter pedido de registro, Sesso 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 LOGIN name passwd GET cpe4001 grade Servidor para o cliente LOGIN succeeded GRADE cpe4001 D Os tipos de mensagens podem ser strings ou inteiros. Por exemplo, HTTP utiliza nmeros inteiros, como 404 para significar "no encontrado" (embora estes nmeros inteiro so escritos como strings). As mensagens do cliente para o servidor e vice -versa so disjuntos: "LOGIN" do cliente para o servidor diferente "Login" do servidor para o cliente. Formato de dados H duas opes 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 contedo da mensagem de acordo com um formato predefinido (como discutido no precedente captulo).
As vantagens so densidade e, portanto, a velocidade. As desvantagens so causadas pela opacidade dos dados: pode ser mais difcil de detectar erros, mais difcil de debug, exigem funes especiais propsito de decodificao. 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 no especificados publicamente, ento um formato de byte podem tambm tornar mais difcil para os outros a fazer engenharia reversait! Pseudocdigo para um servidor byte formato handleClient(conn) { while (true) { byte b = conn.readByte( ) switch (b) { case MSG_1: ... case MSG_2: ... ... } } } Go tem suporte bsico para o gerenciamento de fluxos de bytes. A interfaceConn tem mtodos (c Conn) Read(b [ ]byte) (n int, err os.Error) (c Conn) Write(b [ ]byte) (n int, err os.Error) e estes mtodos so implementados pelos UDPConn e Tcpconn .
O incio da primeira linha da mensagem tipicamente uma palavra que representa o tipo de mensagem. Funes de manipulao de string pode ser usado para decodificar o tipo de mensagem e dados. O resto da primeira linha e linhas sucessivas contm os dados. Funes orientadas para a linha e convenes orientada de linha so usados para gerenciar isso. Pseudocdigo handleClient(conn) { while (true) { byte b = conn.readByte( ) switch (b) { case MSG_1: ... case MSG_2: ... ... } } } Formatos de caracteres so mais fceis de configurar e mais fcil de depurar. Por exemplo, voc pode usar telnet para se conectar a um servidor em qualquer porta, e enviar as solicitaes do cliente para o servidor. No to fcil para o outro lado, mas voc pode usar ferramentas como para espionar o trfego TCP tcpdump e ver imediatamente o que os clientes esto enviando para os servidores. No h o mesmo nvel de suporte em Go para o gerenciamento de fluxos de caracteres. H problemas significativos com conjuntos de caracteres e codificaes de caracteres, e vamos explorar estas questes em um captulo posterior. Se ns apenas fingir que est tudo ASCII, como se fosse mais um momento, ento formatos de caracteres so bastante simples de lidar. A principal complicao a este nvel 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 no assumem '\ n'. Exemplo Simples Este exemplo trata de um protocolo de pesquisa em diretrio basicamente uma verso simplificada do FTP, mas, mesmo sem a transferncia de arquivos parte. Ns s considerar listando um nome de diretrio, listar o contedo de um diretrio e mudar o diretrio atual tudo sobre o lado do servidor, claro. Este um exemplo trabalhado completa de criao de todos os componentes de uma aplicao cliente servidor. uma simples programa que inclui mensagens em ambos os sentidos, assim como o projeto de protocolo de mensagens. Olhe para um programa no cliente servidor simples que permite listar arquivos em um diretrio e alterar e imprimir o diretrio no servidor. Ns omitir copiar arquivos, como que aumenta a durao do programa, sem realmente a introduo de conceitos importantes. Para simplicidade, todos os nomes de arquivo ser assumida para a 7bit ASCII. Se ns apenas olhou para um aplicativo independente em primeiro lugar, em seguida, o pseudocdigo seria
read line from user while not eof do if line == dir list directory 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 aplicao no distribuda seria apenas vincular o cdigo UI e arquivo de acesso
Em uma situao de cliente servidor, o cliente seria para o usurio estreitol, conversando com um servidor em outro lugar. Aspectos deste programa pertencem somente no estreitol de apresentao, tais como a obteno dos comandos do usurio. Algumas so mensagens do cliente para o servidor, alguns so apenas no estreitol do servidor.
Para um navegador de diretrios simples, suponha que todos os diretrios e arquivos esto no estreitol do servidor, e estamos apenas transferindo arquivo a informao a partir do servidor para o cliente. O lado do cliente (incluindo aspectos de apresentao) vai se tornar read line from user while not eof do if line == dir list directory
client request server response dir send list of files change dir cd <dir> send error if failed send 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 sequncias de caracteres para uma listagem de diretrio. Neste caso, no precisa dos pesados Tcnicas dever de serializao do ltimo captulo. Neste caso, podemos usar um formato de texto simples.
Todas as mensagens so em 7bit USASCII As mensagens so casesensitive. Cada mensagem composta por uma sequncia de linhas A primeira palavra na primeira linha de cada mensagem descreve o tipo de mensagem. Todas as outras palavras so os dados da mensagem Todas as palavras so separadas por exatamente um caractere de espao Cada linha denunciado por CRLF
Algumas das escolhas feitas acima so 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 minsculas antes decodificao Uma quantidade arbitrria de espao em branco poderia ser deixado entre as palavras. Isso s acrescenta um pouco mais de complicao, comprimindo branco espao Caracteres de continuao, como '\' pode ser usado para quebrar linhas longas ao longo de vrias linhas. Isto comea 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 difcil
Todas estas variaes existir em protocolos reais. Cumulativamente, eles fazem o processamento de strings apenas mais complexa do que no nosso caso.
server response send list of files, one per line terminated by a blank line change dir send "ERROR" if failed send "OK" send current working directory
Cdigo 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"
Lista do cliente
/* FTPClient */ package main import ( "fmt" "net" "os" "bufio" "strings" "bytes" ) / / strings used by the user interface const ( uiDir = "dir" uiCd = "cd" uiPwd = "pwd" uiQuit = "quit" ) / / strings used across the network const ( 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")
Estado Aplicaes muitas vezes fazem uso de informaes de estado para simplificar o que est acontecendo. Por exemplo
Manter ponteiros de arquivos para o local do arquivo atual Mantendo a posio atual do mouse Manter o valor do cliente atual.
Em um sistema distribudo, tais informaes de estado pode ser mantido no cliente, no servidor, ou em ambos. O ponto importante que se um processo manter informaes de estado sobre si ou sobre o outro processo. Um processo pode manter informaes de estado tanto sobre si mesmo como ele quer, sem causar quaisquer problemas. Se ele precisa para manter as informaes sobre o estado de outro processo, ento 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 atualizao, ou por erros s / w. Um exemplo a leitura de um arquivo. Em aplicaes de processos individuais do cdigo de manipulao de arquivo executado como parte da aplicao. Ele mantm uma arquivos de concursos pblicos e localizao em cada um deles. Cada vez que uma leitura ou gravao feita neste local arquivo atualizado. No sistema de arquivos do D o servidor de arquivo mantm 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 no 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
Se o servidor mantm informaes sobre o cliente, ento ele deve ser capaz de se recuperar se o cliente deixa de funcionar. Se a informao no for salvo, em seguida, em cada transao o cliente deve transferir informaes suficientes para que o servidor para funcionar. Se a conexo no confivel, ento manipulao adicional devem estar no local para garantir que os dois no ficam fora de sincronia. O clssico exemplo de transaes bancrias onde as mensagens se perder. Um servidor de transao pode precisar de ser parte do cliente sistema do servidor. Aplicao Estado Diagrama de Transio Um diagrama de transio de estado mantm o controle do estado atual de um aplicativo e as mudanas que mov-lo para novos estados. Exemplo: transferncia de arquivos com login:
Transition Next state login failed login login succeeded file transfer
SITE OFICIAL: http://golang.org/ dir get logout quit file transfer file transfer login -
file transfer
Diagramas de transio de estado Cliente O diagrama de estado cliente deve seguir o diagrama de aplicativo. Tem mais detalhes, porm: ele escreve e depois l
file transfer
logout
Read FAILED LOGIN name password SUCCEEDED SUCCEEDED CD dir FAILED #lines + contents GET filename ERROR #files + filenames DIR ERROR quit none none login
Write
Next state login file transfer file transfer file transfer file transfer file transfer file transfer file transfer quit
Diagramas de transio de estado do servidor O diagrama de estado do servidor tambm deve seguir o diagrama de aplicativo. Ele tambm tem mais detalhes: ele l e escreve
file transfer
logout
Write FAILED LOGIN name password SUCCEEDED SUCCEEDED CD dir FAILED #lines + contents GET filename ERROR #files + filenames DIR ERROR quit none none login
Read
Next state login file transfer file transfer file transfer file transfer file transfer file transfer file transfer quit
Pseudocdigo Servidor
conjuntos de caracteres e codificaes de Gesto H muitas lnguas em uso em todo o mundo, e eles usam muitos diferentes conjuntos de caracteres. H tambm muitas maneiras de codificar os conjuntos nos binrios formatos de bytes. Este captulo considera algumas das questes no presente. Era uma vez, havia EBCDIC e ASCII ... Na verdade, nunca foi to simples e acaba de se tornar mais complexo ao longo do tempo. H luz no horizonte, mas algumas estimativas so de que ele pode ser de 50 anos antes de todos ns vivemos na luz do dia sobre isso! Os primeiros computadores foram desenvolvidos nos pases de lngua Ingls de os EUA, Reino Unido e Austrlia. Como resultado disto, suposies foram feitas sobre a lngua e conjuntos de caracteres em uso. Basicamente, o alfabeto latino foi usado, alm de nmeros, caracteres de pontuao e alguns outros. Estes foram ento codificados em bytes usando ASCII ou EBCDIC. Os mecanismos de manipulao de caracteres foram baseados sobre isso: arquivos de texto e I / O consistiu em uma sequncia de bytes, com cada byte representando um nico personagem. Comparao de string poderia ser feito por correspondncia bytes correspondentes; converses de superior para minscula pode ser feito atravs do mapeamento de bytes individuais, e assim por diante. H cerca de 6.000 lnguas vivas no mundo (3.000 deles em Papua Nova Guin!). Alguns idiomas utilizam o "Ingls", mas a maioria no. As lnguas romnicas, como o francs tem adornos em vrios personagens, de modo que voc pode escrever J'ai arrt", com duas vogais acentuadas de forma diferente. Da mesma forma, as lnguas germnicas tm personagens extras, como ''. Mesmo Reino Unido Ingls tem caracteres no no conjunto padro ASCII: o smbolo de libra "E." e, recentemente, o euro '' Mas o mundo no est restreito s variaes no alfabeto latino. Tailndia tem seu prprio alfabeto, com palavras parecido com isto: " ". H muitos outros alfabetos e Japo ainda tem dois, Hiragana e Katagana. H tambm as lnguas hierographic como o chins, onde voc pode escrever " , ". Seria bom do ponto de vista tcnico, se o mundo acabou de usar ASCII. No entanto, a tendncia no sentido oposto, com mais e mais usurios exigentes que software usar a linguagem que eles esto familiarizados. Se voc criar um aplicativo que pode ser executado em diferentes pases, ento os usurios vo exigir que ele usa sua prpria lngua. Em um sistema de distribuio, diferentes componentes da sistema pode ser usado por usurios que esperam diferentes idiomas e caracteres. Internacionalizao (i18n) a forma como voc escreve suas aplicaes para que eles possam lidar com a variedade de lnguas e culturas. Localizao (l10n) o processo de personalizar seu aplicativo internacionalizado a um grupo cultural
A codificao mais comum para ASCII utiliza os pontos de cdigo de bytes de 7 bits, de modo que a codificao de "A", por exemplo, de 65. Este conjunto realmente ASCII EUA. Devido aos desejos europeus para caracteres acentuados, alguns caracteres de pontuao so omitidos para formar um conjunto mnimo, ISO 646, enquanto h "variantes nacionais" com personagens europeias adequadas. A pgina http:/ /www.cs.tut.fi/jkorpela/chars.html por Jukka Korpela tem mais informaes para os interessados. No vamos precisar deles variantes embora. ISO 8859
UTF32 uma codificao de 4 bytes, mas no 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 no ISO 88591) UTF7 usado algumas vezes, mas no comum
UTF8: Go e runes UTF8 a codificao mais comumente usado. Google estima que 50% das pginas que ele v so codificados em UTF8. O Conjunto ASCII tem os mesmos valores de codificao 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 codificao UTF8. Em termos de personagens, uma string uma array de runes. Uma string tambm 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, trs ou quatro bytes. Isto significa que o comprimento de uma cadeia de caracteres (runes) no geralmente o mesmo que o comprimento do seu array de bytes. Eles s so iguais quando a string composto por
_, 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 }
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 srie ISO 8859 so conjuntos de caracteres de 8 bits para diferentes partes da Europa e algumas outras reas. Todos eles tm o conjunto ASCII comum na parte de baixo, mas diferem na sua parte superior. Segundo o Google, cdigos ISO 8859 representam cerca de 20% das pginas da web que v. O primeiro cdigo, 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 codificao padro ISO 88591. Mas isso realmente no ajuda muito, como UTF16 um 16bit codificao e ISO 88591 uma codificao de 8 bits. UTF8 uma codificao de 8 bits, mas ele usa o top bit para sinalizar bytes extras, portanto, apenas o Subconjunto ASCII sobrepe para UTF8 e ISO 88591. Ento UTF8 no ajuda muito. Mas a srie ISO 8859 no tem quaisquer problemas complexos. Para cada personagem em cada conjunto corresponde um carcter nico Unicode. Por exemplo, na ISO 88592, o caractere "letra maiscula latina I com ogonek" tem ISO 88592 0xc7 ponto de cdigo (em hexadecimal) e correspondente ponto de U 012 E. cdigo 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 cdigo para pontos de cdigo Unicode poderia ser feito como um array de 256 inteiros. Mas muitos destes vontade tem o mesmo valor que o ndice. Ento, s usar um mapa dos diferentes, e aqueles que no 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 funo para converter UTF8 strings para uma array de ISO 88592 bytes
/* 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 srie 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 funes podem ser usadas para ler e escrever UTF8 strings como ISO 88592 bytes. Ao alterar a tabela de mapeamento, voc pode cobrir os outros cdigos ISO 8859. Latin1 ou ISO 88591, um caso especial o mapa exceo vazio como os pontos de cdigo para Latin1 so os mesmos em Unicode. Voc tambm pode usar a mesma tcnica 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 codificaes. 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, ento 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 codificao de caracteres 2022 minimizado conjunto de caracteres tamanhos usando uma mquina de estado finito para trocar as pginas de cdigo de entrada e sada. Este foi emprestado por alguns dos japoneses codificaes, e torna as coisas muito complexas.
Segurana Embora a internet foi originalmente concebido como um sistema para suportar atacks por agentes hostis, desenvolveu-se em uma cooperativa ambiente de entidades relativamente confiveis. Infelizmente, esses dias esto muito longe. Spam, ataques de negao de servio, as tentativas de phishing e assim por diante so indicativos de que qualquer pessoa que utilize a internet o faz por sua conta e risco. As candidaturas devem ser construdos para funcionar corretamente em situaes hostis. "Corretamente" j no significa apenas ficar os aspectos funcionais do programa correto, mas tambm significa garantir a privacidade e integridade dos dados transferidos, o acesso apenas a usurios legtimos e outros questes. Isto, obviamente, faz com que seus programas muito mais complexa. H difceis e sutis problemas de computao envolvidos na realizao aplicaes seguras. As tentativas de faz -lo sozinho (como inventar suas prprias bibliotecas de criptografia) so normalmente fadada ao fracasso. Em vez disso, voc precisa fazer uso de bibliotecas projetados por profissionais de segurana arquitetura de segurana ISO O modelo de sete camadas ISO OSI (interligao de sistemas abertos), de sistemas distribudos bem conhecida e repetida nesta figura:
O que menos conhecido que a ISO construda toda uma srie de documentos sobre esta arquitetura. Para os nossos propsitos aqui, o mais importante o modelo de Arquitetura de Segurana ISO, ISO 74982. Funes e nveis As principais funes exigidas de um sistema de segurana so
Autenticao prova de identidade A integridade dos dados os dados no so adulterados Sigilo dados no est exposta a outros Cartrio / assinatura O controle de acesso Garantia / disponibilidade
Estes so necessrios para os seguintes nveis de pilha OSI:
SITE OFICIAL: http://golang.org/ Autenticao da origem de dados (3, 4, 7) Servio de controle de acesso (3, 4, 7) Confidencialidade de conexo (1, 2, 3, 4, 6, 7) Confidencialidade conexo (1, 2, 3, 4, 6, 7) Confidencialidade campo Seletiva (6, 7) Fluxo de trfego confidencialidade (1, 3, 7) A integridade da conexo com a recuperao (4, 7) A integridade da conexo sem recuperao (4, 7) Campo seletiva integridade de conexo (7) Campo seletiva integridade sem conexo (7) No repdio na origem (7) No repdio de recepo (7) Peer entidade autenticao Criptografia Assinatura digital Troca de autenticao
Autenticao da origem de dados
Listas de controle de acesso Senhas Capacidades listas Rtulos Confidencialidade de conexo ecryption Controle de roteamento Confidelity sem conexo Criptografia Controle de roteamento Confidelity campo seletiva Criptografia Fluxo de trfego confidelity Criptografia Preenchimento trfego Controle de roteamento A integridade da conexo com recuperao Criptografia A integridade dos dados A integridade da conexo sem recuperao Criptografia A integridade dos dados Campo seletivo a integridade da conexo Criptografia A integridade dos dados Integridade sem conexo Criptografia Assinatura digital A integridade dos dados Campo seletiva integridade sem conexo Criptografia Assinatura digital A integridade dos dados No repdio na origem
/* 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( ) }
/* 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 coleo de chaves pblicas, juntamente
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 call cert, 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) {
var buf [512]byte for { fmt.Println("Trying to read") n, err := conn.Read(buf[0:]) 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
A World Wide Web um grande sistema distribudo, com milhes de usurios. Um site pode tornar -se um host da Web, executando um servidor HTTP servidor. Enquanto os clientes da Web normalmente so os usurios com um navegador, existem muitos outros "agentes de usurio", como aranhas, web clientes de aplicativos e assim por diante. A Web construdo em cima do HTTP (HyperTexto Transport Protocol), que est no topo das camadas TCP. HTTP tem sido atravs de trs verses disponveis publicamente, mas o mais recente verso 1.1 agora o mais comumente usado. Neste captulo vamos dar uma viso geral do HTTP, seguido pelo Go APIs para gerenciar conexes HTTP. Vista de HTTP URLs e recursos URLs especificar a localizao de um recurso. Um recurso muitas vezes um arquivo esttico, como um documento HTML, uma imagem ou um arquivo de som. Cada vez mais, pode ser um objeto gerado dinamicamente, talvez, com base nas informaes armazenadas num banco de dados. Mas Quando um agente de usurio solicita um recurso, o que retornado no o recurso em si, mas alguns representao desse recurso. Para exemplo, se o recurso um arquivo esttico, ento o que enviado para o agente de usurio uma cpia do arquivo. Mltiplas URLs podem apontar para o mesmo recurso, e um servidor HTTP retornar representaes adequadas do recurso para cada URL. Por exemplo, uma empresa pode tornar a informao produto disponvel tanto interna como externamente, utilizando diferentes URLs para o mesmo produto. A representao interna do produto pode incluir informaes como agentes de contato internas para a produto, enquanto que a representao externa pode incluir a localizao 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 usurio para os servidores e retornar um fluxo de bytes, enquanto um servidor pode ter para fazer qualquer quantidade de processamento do pedido. Caractersticas HTTP HTTP um, sem conexo, protocolo confivel aptrida. Na forma mais simples, a cada pedido de um agente do usurio tratado de forma confivel e em seguida, a conexo quebrada. Cada pedido envolve uma conexo TCP em separado, por isso, se muitas reources so necessrios (como imagens incorporado em uma pgina HTML), ento muitas conexes TCP tem que ser configurado e derrubado em um curto espao de tempo. Ter muitas optimizaes em HTTP, que aumentam a complexidade da estrutura simples, a fim de criar uma forma mais eficiente e fivel protocolo. Verses Existem 3 verses do HTTP Verso 0.9 totalmente obsoleto Verso 1.0 quase obsoleto Verso 1.1 atual Cada verso deve entender as solicitaes e respostas de verses anteriores. HTTP 0.9
A Linha de Status fornece informaes sobre o destino do pedido: Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF Ex: HTTP/1.0 200 OK Os cdigos so 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 cabealho contm informaes 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 OK Date: Fri, 29 Aug 2003 00:59:56 GMT Server: Apache/2.0.40 (Unix) Accept-Ranges: bytes Content-Length: 1595 Connection: close Content-Type: text/html; charset=ISO-8859-1 HTTP 1.1 HTTP 1.1 correes de muitos problemas com HTTP 1.0, mas mais complexo por causa disso. Esta verso feita atravs da extenso ou reestreitomento do opes disponveis 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
Identificao hostname (permite hosts virtuais) Negociao de contedo (vrios idiomas) Conexes persistentes (reduz despesas gerais TCP isto muito confuso) Transferncias fragmentada Intervalos de bytes (solicitao de partes de documentos) Suporte a proxy
O protocolo 0.9 tomou uma pgina. O protocolo foi descrito em 1.0 a cerca de 20 pginas. 1.1 tem 120 pginas. Simples usurio agentes Os agentes do usurio 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 usurio "Cabea", que pede informaes sobre um recurso e seu servidor HTTP. A funo 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 cabealho do HTTP resposta. Um programa para fazer esse pedido e apresentar os resultados /* Head */ package main import (
type Request struct { Method string / / GET, POST, PUT, etc. RawURL string / / The raw URL given in the request. URL *URL / / Parsed URL. 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
Existe uma grande quantidade de informao que pode ser armazenada em um pedido. Voc no precisa preencher todos os campos, apenas aqueles de interesse. O mais sim maneira de criar um pedido com os valores padro 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 padro definido ISO88591 sempre recebe um valor de um a menos que explicitamente mencionado na lista.). Um cliente de criao de um pedido charset simples pelo acima. Mas h uma certa confuso 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 mdia do contedo, como. Se adequado, o tipo de mdia deve declarar o charset, como text / html; charset = UTF8. Se no houver nenhuma charset text / html especificao, em seguida, de acordo com a especificao HTTP ele deve ser tratado como padro ISO88591 charset. Mas o HTML 4 especificao afirma que uma vez que muitos servidores no se conformam com isso, ento voc no pode fazer suposies. Se h uma codificao especificada no servidor, Em seguida, assumir que correto se no houver nenhum especificado, uma vez que 50% das pginas ContentType esto em UTF8 e 20% esto em ASCII, ento seguro assumir UTF8. Apenas 30% das pginas pode ser errado. O objeto Cliente Para enviar um pedido a um servidor e obter uma resposta, o objeto de convenincia Cliente a maneira mais fcil. Este objeto pode lidar com mltiplas pedidos e vai cuidar de questes como se o servidor mantm a conexo TCP vivo, e assim por diante. Isto ilustrado no seguinte programa
/* 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))
conexes HTTPS por clientes Para conexes seguras e criptografadas, HTTP usa TLS, que descrito no captulo sobre segurana. O protocolo de HTTP + TLS chamado HTTPS e usa URLs https:/ / em vez de http:/ / urls. Os servidores so obrigados a devolver os certificados X.509 vlidos antes de um cliente aceitar dados a partir deles. Se o certificado vlido, ento Go lida com tudo sob o cap e os clientes dadas anteriormente executar bem com URLs HTTPS. Muitos sites tm certificados invlidos. 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!" boto, 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 no tenho que trabalhar ainda. Portanto, no h exemplo atual de "exercer, em face da adversidade:)". Talvez mais tarde. servidores O outro lado para a construo de um cliente um servidor Web manipulao de solicitaes HTTP. As mais simples e mais antirs os servidores apenas devolvidos cpias de arquivos. No entanto, qualquer URL agora pode desencadear um clculo arbitrrio em servidores atuais. O servidor de arquivos Comeamos com um servidor de arquivos bsico. Go fornece uma multiplexer, Ou seja, um objeto que Ir ler e interpretar solicitaes. Ele distribui pedidos para que funcionam em seu prprio segmento. Assim, grande parte do trabalho de ler solicitaes HTTP, decodificando -os e manipuladores ramificando para funes adequadas em seu prprio segmento feito por ns. Para um servidor de arquivos, Go tambm d uma FileServer objeto que sabe como entregar os arquivos do sistema de arquivos local. preciso um "root" diretrio que o topo de uma rvore de arquivos no sistema local, e um padro para corresponder URLs contra. O padro 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 embaraosamente trivial dado a esses objetos. /* File Server */ package main
O segundo argumento para HandleAndServe pode ser nil, em seguida, as chamadas so enviados para todos os manipuladores registrados. Cada manipulador HandleAndServe deve ter um padro de URL diferente. Por exemplo, o manipulador de arquivo pode ter padro de URL "/" enquanto um manipulador de funo pode ter Padro de URL "/ cgibin". Um padro mais especfica prevalece sobre um padro mais geral. Programas CGI comuns so testcgi (Escrito no shell) ou printenv (Escrito em Perl), que imprime os valores do ambiente variveis. 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"))
Nota: para simplificar este programa no entregar HTML bem formado. Est faltando html, cabea e corpo marcas. Usando o cgibin diretrio neste programa um pouco atrevido: no chamar um programa externo como scripts CGI fazer. Ele s chama a Go funo. Go tem a capacidade de chamar programas externos usando os.ForkExec, Mas ainda no tem suporte para dinamicamente mdulos conectveis como Apache do mod_perl Ignorando o multiplexer padro Solicitaes HTTP recebidas por um servidor Go geralmente so tratadas por um multiplexer os examina o caminho no pedido HTTP e chamadas o manipulador de arquivo apropriado, etc Voc pode definir seus prprios manipuladores. Estas podem ser registrados com o multiplexer por inadimplncia http.HandleFunc chamada o que leva a um padro e uma funo nil. As funes, tais como em seguida ListenAndServe , tomar uma nil funo. Isto foi feito no ltimo exemplo. Se voc quiser assumir o papel multiplexer ento voc pode dar uma funo diferente de zero como a funo do manipulador. Esta funo ser ento totalmente responsvel pela gesto dos pedidos e respostas. O exemplo a seguir trivial, mas ilustra a utilizao do presente: a funo retorna um multiplexador simplesmente "204 Nenhum contedo" para todos pedidos: /* ServerHandler */ package main import ( "net/http" )
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 sada padro /** * PrintPerson */ package main import ( "fmt" "html/template" "os"
No uso que est interessado, deve haver apenas um argumento para a funo que Ir ser uma string. Funes em virr no Go biblioteca de modelos tm algum cdigo inicial para lidar com casos de no conformidade, de modo que basta copiar isso. Em seguida, ele apenas simples string manipulao para alterar o formato do endereo de e-mail. Um programa /** * PrintEmails */ 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) } }
A sada est The name is jan. An email is "jan at newmarch.name" An email is "jan.newmarch at gmail.com" Variveis O pacote de modelo permite que voc definir e usar variveis. Como motivao para isso, considerar como podemos imprimir cada pessoa da endereo de e -mail prefixado pelo seu nome. O tipo que usamos novamente Para acessar as strings de e-mail, ns usamos um declarao range como {{range .Emails}} {{.}} {{end}} Mas nesse momento, no podemos acessar o campo Name como '.' agora est atravessando os elementos da array e da est fora deste escopo. A soluo guardar o valor do campo de uma varivel que pode ser acedida em qualquer lugar o seu mbito. Variveis em modelos so prefixados por '$'. Ento ns 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{ 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 sada Name is jan, email is [email protected] Name is jan, email is [email protected] declaraes condicionais Continuando com a nosso exemplo Person, supondo que ns s queremos imprimir a lista de e-mails, sem cavar nele. Ns podemos fazer isso com um modelo Name is jan Emails are [[email protected] [email protected]] Isto Ir imprimir Nome janeiro Emails so [[email protected] jan.newmarch @ gmail.com] Porque assim que a fmt pacote Ir mostrar uma lista. Em muitas circunstncias que podem ficar bem, se isso que voc quer. Vamos considerar um caso em que quase certo, mas no bem assim. L um pacote de JSON de serializao de objetos, o que ns verificamos no Captulo 4. Isso produziria {"Name": "jan", "Emails": ["[email protected]", "[email protected]"] } O pacote JSON o que voc usaria na prtica, mas vamos ver se ns podemos produzir sada JSON usando modelos. Podemos fazer algo semelhante apenas pelos modelos que temos. Isto quase como um
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) {
Concluso O pacote de modelo Go til para certos tipos de transformaes de texto que envolvem a insero de valores de objetos. Ele no tem o poder de, por exemplo, as expresses regulares, mas mais rpida e, em muitos casos, ser mais fcil de usar do que as expresses regulares
Captulo 10 Um servidor da Web completa Este captulo , principalmente, uma ilustrao longo do captulo HTTP, a construo de um servidor Web completo em Go. Ele tambm mostra como usar modelos para usar expresses em arquivos de texto para inserir os valores das variveis e gerar sees repetidas.
Introduo Estou aprendendo chins. Em vez disso, depois de muitos anos de tentativas eu ainda estou tentando aprender chins. Claro que, em vez de para baixo flambagem e ficando com ela, eu tentei todos os tipos de ajudas tcnicas. Tentei DVDs, vdeos, flashcards e assim por diante. Eventualmente, eu percebi que l no 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, no foi bem escrito e depois de algumas tentativas de transform-lo de cabea para baixo e de dentro para fora, cheguei concluso de que era melhor para comear do zero. claro, uma soluo Web seria muito melhor do que um autnomo, porque ento todas as outras pessoas da minha turma chins 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 pgina composta por uma lista de conjuntos de cartes, atualmente disponveis, como voc quer um conjunto apresentado (ordem carta aleatria, chins, Ingls ou aleatrio), se deseja exibir um conjunto, adicionar a ele, etc Passei muito tempo constru-lo de alguma forma o meu chins no progrediu muito enquanto eu estava fazendo isso ... Ele provavelmente no vai ser muito emocionante como um programa, se voc no quer aprender chins, mas vamos entrar na estrutura. Pginas estticas Algumas pginas ter apenas contedo esttico. Estes podem ser gerenciados por um fileServer . Para simplificar eu coloquei todo o HTML esttico pginas e arquivos CSS no htmldiretrio e todos os arquivos Java Script na jscript diretrio. Estes so, ento, entregue pelo Go cdigo fileServer := http.FileServer("jscript", "/jscript/") http.Handle("/jscript/", fileServer) fileServer = http.FileServer("html", "/html/") http.Handle("/html/", fileServer) Modelos A lista de conjuntos de cartes, em aberto, dependendo do nmero de arquivos em um diretrio. Estes no devem ser codificado em um Pgina HTML, mas o contedo deve ser gerado, conforme necessrio. Este um candidato bvio para modelos.
Como este utilizado ilustrado pela funo lookupWord. Isto chamado em resposta a um pedido de formulrio HTML para encontrar o Ingls palavras em um dicionrio.
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)
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)
de := Entry{ Traditional: trad, Simplified: simp, Pinyin: pinyin, Translations: translations} 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 }
Cartes Fash Cartes Fash um tipo flash cardis type FlashCard struct { Simplified string English string Dictionary *dictionary.Dictionary } No momento ns s armazenar o carter simplificado e traduo Ingls para esse personagem. Temos tambm um Dicionrio que conter apenas uma entrada para a entrada, vamos ter escolhido algum lugar. Um conjunto de cartes de memria flash definido pelo tipo de
type FlashCards struct { Name string CardOrder string ShowHalf string Cards [ ]*FlashCard
Onde o CardOrder ser "aleatrio" ou "sequencial" e o ShowHalf ser "RANDOM_HALF" ou "ENGLISH_HALF" ou "CHINESE_HALF" para determinar que a metade de um novo carto exibido pela primeira vez. O cdigo para cartes de memria flash no tem nada de novo nela. Recebemos os dados do navegador do cliente e usar JSON para criar um objeto da dados de formulrio 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)
flashCardsNames := flashcards.ListFlashCardsNames( ) t, err := template.ParseFiles("html/ListFlashcards.html") if err != nil { http.Error(rw, err.Error( ), http.StatusInternalServerError) return } 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")
Outros Bits: Java Script e CSS No pedido, um conjunto de flashcards ser carregada no navegador. Um conjunto muito abreviado mostrada abaixo. A exibio destes cartes
<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">
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 atravs da Web Go tem mecanismos bsicos para anlise 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 atravs de um grande nmero de verses e HTML 5 est atualmente em desenvolvimento. Houve tambm muitos "Vendedor" verses do HTML, introduzindo marcas que nunca fizeram em padres. HTML simples o suficiente para ser editado manualmente. Consequentemente, muitos documentos HTML so "mal formado", no seguindo a sintaxe a lngua. Parsers HTML em geral, no so muito rirrosos, e aceitar muitos documentos "ilegais". No havia muito nas verses anteriores do Go sobre a manipulao de documentos HTML basicamente, apenas um tokenizador. A natureza incompleta de o pacote levou sua remoo para Go 1. Ele pode ainda ser encontrado na expPacote (experimental), se voc realmente precisa dele. Sem dvida alguma forma melhorou estar disponvel em uma verso posterior do Go, e, em seguida, ele ser adicionado de volta a este livro. No h suporte limitado para HTML no pacote XML, discutido no prximo captulo.
XML XML uma linguagem de marcao significativa destina -se principalmente como um meio de serializadas dados estruturas como um documento de texto. Go tem suporte bsico 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 marcao especializadas, tais como MathML e CML (Qumica 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 nvel mais simples, XML permite que voc deestreito suas prprias marcas para uso em documentos de texto. As tags podem ser aninhadas e podem ser intercalados com o texto. Cada tag tambm pode conter atributos com valores. Por exemplo,
<person> <name> <family> Newmarch </family> <personal> Jan </personal> </name> <email type="personal"> [email protected]
A estrutura de qualquer documento XML pode ser descrito de uma srie de maneiras: A DTD definio do tipo de documento bom para descrever a estrutura Esquema XML so bons para descrever os tipos de dados usados por um documento XML RELAXAR NG proposto como uma alternativa No h discusso sobre o valor relativo de cada modo de definir a estrutura de um documento XML. No vamos comprar em que, como Go no suport qualquer deles. Go no possvel verificar a validade de qualquer documento em um esquema, mas apenas para boa formao. Quatro tpicos so discutidos neste captulo: analisar um fluxo de XML, triagem e unmarshalling dados entrar em XML e XHTML.
Anlise de XML Go tem um parser XML que criado usando. Isso leva um io.Readercomo parmetro e retorna um ponteiro para NewParser Analisador. O principal mtodo deste tipo Smbolo que retorna o prximo token no fluxo de entrada. O token um dos tipos, StartElement, EndElement, CharData, Comment, ProcInst ou Directive. Os tipos so 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 tambm uma estrutura
Nota-se que o analisador inclui todos CharData, incluindo os espaos 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 "
<person> <name> <family> Newmarch </family> <personal> Jan </personal> </name> <email type="personal"> [email protected] </email> <email type="work"> [email protected] </email> </person> Ns gostaramos de mapear este nas estruturas Go Isto requer vrios comentrios: 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 reflexo Go. Isto requer que todos os campos por exemplo pblicas comear com uma letra maiscula. Mais cedo verses do Go utilizado sensvel a maisculas de combinar campos Name tais como o XML string "name" para o campo. Agora, porm, correspondncia maisculas e minsculas usado. Para realizar a prova, os campos de estrutura deve ser marcado para mostrar a sequncia de caracteres em contrapartida. Isso muda Person
type Person struct { Name Name `xml:"name"` Email [ ]Email `xml:"email"` } 2. Enquanto a marcao de campos pode append sequncias de caracteres XML para campos, no pode fazer isso com os nomes das estruturas. Um campo adicional necessrio, com o nome do campo "XMLName". Isso afeta apenas o nvel 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 no tem atributos e s tem dados de caracteres, em seguida, ele corresponde a um campo string com o mesmo nome (caso sensvel, embora). Assim, a marcao xml:"family"com dados de caracteres mapas "Newmarch" para o campo de sequncia Family 6. Mas se a marca tem atributos, ento 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"` }
Existe algum apoio no pacote XML para lidar com documentos HTML, mesmo que eles no so compatvel com XML. O analisador XML discutido anteriormente pode lidar com muitos documentos HTML se for modificada por parser := xml.NewDecoder(r) parser.Strict = false parser.AutoClose = xml.HTMLAutoClose parser.Entity = xml.HTMLEntity
Remote Procedure Call 13.1 Introduo Soquete e programao 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 responsvel pela criao 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 autnomos no fazem muito uso de tcnicas de passagem de mensagens. Geralmente o preferido mecanismo o da funo (Ou mtodo ou procedimento) chamada. Neste estilo, um programa Ir chamar uma funo com uma lista de parmetros, e no estreitol da chamada de funo ter um conjunto de valores de retorno. Estes valores podem ser o valor da funo, ou se endereos foram passados como parmetros, em seguida, o contedo desses endereos podem ter sido alterados. A chamada de procedimento remoto uma tentativa de trazer esse estilo de programao 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 so 1. O cliente chama o procedimento stub local. O stub empacota os parmetros em uma mensagem de rede. Isto chamado triagem. 2. As funes de rede no kernel O / S so chamados pelo stub para enviar a mensagem. 3. O sistema envia a mensagem (s) para o sistema remoto. Isso pode ser orientado a conexo ou sem conexo. 4. Um stub servidor unmarshals os argumentos da mensagem de rede. 5. O stub servidor executa uma chamada de procedimento local. 6. O procedimento concludo, retornando a execuo para o stub servidor.
funo 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 funo vlida F (& T1 e T2) os.Error A restrio em argumentos significa que voc normalmente tem que definir um tipo de estrutura. RPC Go usa a pacote gob para triagem e dados unmarshalling, ento os tipos de argumentos tem que seguir as regras do gob como discutido no captulo anterior. Devemos seguir o exemplo dado na documentao do Go, como isso ilustra os pontos importantes. O servidor executa dois operaes que so triviais que no exigem o "gemido" da RPC, mas so simples de entender. As duas operaes devem multiplicar dois nmeros inteiros, e segunda encontrar o quociente e resto da diviso do primeiro pelo segundo. Os dois valores a serem manipulados so dadas numa estrutura: type Values struct { X, Y int } A soma apenas uma int, Enquanto que o quociente / restante outra estrutura type Quotient struct {
A funo deve ser pblico (comea com uma letra maiscula); Tem exatamente dois argumentos, o primeiro um ponteiro para dados de valor a ser recebido pela
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 no importa qualquer tipo poderia ter feito. Um objeto deste tipo podem agora ser registrados usando, em seguida, seus mtodos podem ser chamados pelo sistema RPC. RPC Servidor HTTP Qualquer RPC precisa de um mecanismo de transporte para receber mensagens atravs 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 cdigo 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 {
RPC cliente HTTP O cliente precisa configurar uma conexo HTTP com o servidor RPC. Ele precisa preparar uma estrutura com os valores a serem enviados, e o endereo de uma varivel para armazenar os resultados dentro Ento ele pode fazer uma chamada com argumentos:
O nome da funo de controle remoto para executar Os valores a serem enviados O endereo de uma varivel para armazenar o resultado em
Um cliente que chama ambas as funes do servidor de aritmtica
/** * 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] 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 verso 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
Notamos que os tipos de argumentos de valor no so os mesmos no cliente e servidor. No servidor, temos usado Values enquanto em que o cliente foi utilizada Args. Isso no importa, j que estamos seguindo as regras da gob serializao, e os nomes um tipos de campos de duas estruturas "corresponder. Melhor prtica de programao diria que os nomes devem ser os mesmos! No entanto, este no apontar uma possvel armadilha em usar Go RPC. Se mudarmos a estrutura no cliente para ser, digamos, type Values struct { C, B int } Depois gob no tem problemas: no lado do servidor o unmarshalling Ir ignorar o valor de busca C dada pelo cliente, e usar o padro valor zero para A Usando Vai RPC requer uma aplicao rgida da estabilidade de nomes de campo e tipos de o programador. Notamos que no existe mecanismo de controle de verso para fazer isso, e nenhum
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)
canais Rede
Aviso O pacote netchan est sendo reformulado. Enquanto ele estava em verses anteriores do Go, ele no est em Go 1. Encontra-se disponvel no old / netchan pacote, se voc ainda precisa dele. Este captulo descreve esta verso antiga. No us -lo para o novo cdigo. Introduo H muitos modelos para o compartilhamento de informaes entre os processos de comunicao. Um dos mais elegante o conceito de Hoare canais. Neste, no h memria compartilhada, de modo que surgir nenhuma das questes relativas ao acesso de memria comum. Em vez disso, um processo de enviar uma mensagem ao longo de um canal para outro processo. Os canais podem ser sncrona ou assncrona, tampo ou sem buffer. Um goroutine gera nmeros inteiros de dois para cima. Estes so bombeados para uma srie de canais que atuam como peneiros. Cada filtro distingue -se por um primo diferente, e ele remove do seu fluxo de cada nmero que divisvel por sua prima. Assim goroutine dos '2 filtra os nmeros pares, enquanto goroutine o '3 'filtra mltiplos de 3. O primeiro nmero 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 eficcia de muitos milhares de goroutines comunicando por muitos milhares de canais depende de quo bem o implementao destas primitivas feito. Go projetado para otimizar estes, de modo que este tipo de programa vivel. V tambm suporta canais distribudos usando o pacote netchan. Mas as comunicaes de rede so milhares de vezes mais lento do que comunicaes de canal em um nico computador. Executando uma peneira em uma rede atravs de TCP seria ridiculamente lento. No entanto, ele d uma opo de programao que pode ser til em muitas situaes. 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 tm um canal compartilhado em que eles podem se comunicar. Note se que a comunicao uniidirecional: se voc quiser enviar informaes para os dois lados, abrir dois canais de um para cada direo. servidor Canal A fim de fazer um canal visvel para os clientes, voc precisa exportar isso. Isto feito atravs da criao de um exportador usando NewExporter com nenhuma parmetros. O servidor chama ento para lsiten e lidar com as respostas. Isso leva dois parmetros, sendo o primeiro o ListenAndServe subjacente mecanismo de transporte, tais como "tcp" e segundo o endereo de escuta de rede (geralmente apenas um nmero de porta. Para cada canal, o servidor cria um canal local normal e, em seguida, chama para ligar est para a
Nota: no momento da escrita, o servidor ser, por vezes, falhar com uma mensagem de erro "exportao netchan: resposta do cliente codificao de erro". Isso registrado como Issue 1805 cliente Canal
A fim de encontrar um canal de exportao, o cliente deve importar lo. Isto criado usando que tem um protocolo e uma rede Importao endereo do servio de "host: port". Este , ento, usado para importar um canal de rede pelo nome e vincul -lo a um canal local. Note-se que variveis de canal so referncias, para que voc no precisa passar os seus endereos de funes 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: /* 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 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 so projetados para responder a um problema comum com sistemas web: o servidor incapaz de iniciar ou enviar contedo para um agente de usurio como um navegador. Teia soquetes de permitir uma conexo full duplex a ser estabelecido para permitir isso. Go tem quase suporte completo para eles. 15.1 Aviso O pacote Web Sockets no est atualmente no principal Go uma rvore e no est includo nas distribuies atuais. Para us-lo, voc precisa de para instal-lo por go get code.google.com/p/go.net/websocket 15.1 Introduo O modelo websockets mudar para R61 lanamento. Este descreve o novo pacote, no o pacote de r60 e anteriores. Se voc fizer R61 no tem, no momento da escrita atualizao semanal, usar hg pull; hg update weekly para baix-lo. O modelo padro de interao entre um agente de usurio da web como um navegador e um servidor web como o Apache que o usurio agente faz solicitaes 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 endereos, clicando nos botes frente ou para trs, etc A resposta tratada como uma nova pgina e carregado em uma janela do navegador. Este modelo tradicional tem muitos inconvenientes. A primeira de que cada pedido abre e fecha uma nova ligao TCP. HTTP 1.1 resolvido isso, permitindo que as conexes persistentes, de modo que uma conexo pode ser mantida aberta por um curto perodo para permitir mltiplas pedidos (por exemplo, imagens) a ser feito no mesmo servidor. Enquanto HTTP 1.1 conexes persistentes aliviar o problema de carregamento lento de uma pgina com muitos grficos, ele no melhorar o modelo de interao. Mesmo com as formas, o modelo ainda o de submeter o formulrio e exibir a resposta como uma nova pgina. Java Script ajuda em permitir a verificao a ser realizada em dados do formulrio antes da apresentao de erro, mas no muda o modelo. AJAX (Asynchronous Java Script and XML) fez um avano significativo para o modelo de interao do usurio. Isto permite que um navegador de fazer um pedido e usar apenas a resposta para atualizar a exibio no local usando o Document Object Model (DOM) HTML. Mas novamente o modelo de interao o mesmo. AJAX s afeta o modo como o navegador gerencia as pginas retornadas. No h extras explcita apoio em Go para AJAX, como nenhum necessrio: o servidor HTTP s v uma solicitao HTTP POST comum com, possivelmente, alguns XML ou JSON dados, e esta pode ser tratada com o uso de tcnicas j discutidas. Todos estes ainda so navegador para comunicao do servidor. O que est faltando o servidor iniciado comunicaes para o navegador. Esta lata ser preenchido por soquetes da Web: o navegador (ou qualquer agente do usurio) mantm aberta uma conexo TCP de longa durao a um servidor Web Sockets. Conexo TCP permite que cada lado para enviar pacotes arbitrrios, portanto, qualquer protocolo de aplicao pode ser utilizado em um soquete web. O Como um websocket iniciado pelo agente do usurio enviando uma solicitao HTTP especial que diz "mudar para soquetes web". O TCP conexo subjacente a solicitao HTTP mantida aberta, mas ambos agente do usurio e chave do servidor para utilizar o protocolo soquetes web em vez de comear uma resposta HTTP e fechar o socket. Note-se que ele ainda o navegador ou agente de usurio que inicia a conexo de soquete web. O navegador no executar um servidor TCP de prpria. Enquanto a especificao complexo, o protocolo projetado para ser bastante fcil de usar. O cliente abre uma conexo HTTP e, em seguida, substitui o protocolo HTTP com o seu prprio protocolo WS, reutilizando a mesma conexo TCP. Servidor Web socket
msgToSend := "Hello" err := websocket.Message.Send(ws, msgToSend) var msgToReceive string err := websocket.Message.Receive(conn, &msgToReceive) Cdigo 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 (
/* EchoClient */ package main import ( "code.google.com/p/go.net/websocket" "fmt" "io" "os" ) func main( ) { if len(os.Args) != 2 {
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 = 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 {
O Codec tipo O Message e JSON objetos so ambos instncias 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 mtodos utilizados anteriormente. provvel que websockets tambm Ir ser utilizado para a troca de dados XML. Ns podemos construir um XML Codec objeto envolvendo o XML marechal e mtodos desempacotar discutidos Captulo 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, ento, publicando objetos Go como uma Personkem um documento XML e envilo a partir de um cliente para um servidor por
/* 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 informaes para o console package main import ( "code.google.com/p/go.net/websocket" "fmt" "net/http"
MODULO 2 LINGUAGEM GO
INTRODUO A LINGUAGEM GO
Cdigo menos, compilar mais rpido, mais rpido executar => ter mais diverso!
Este texto apresenta o tratamento mais abrangente da linguagem de programao Go voc pode encontrar. Inspira-se em todo o espectro de fontes Go disponveis: documentao e blogs, livros, artirs, udio e vdeo, e minha prpria experincia em engenharia de software e linguagens de programao de ensino e bases de dados, organizando os conceitos e tcnicas de uma forma sistemtica online. Vrios pesquisadores e desenvolvedores da Google experimentou a frustrao com os processos de desenvolvimento de software dentro da empresa, particularmente usando C + + para escrever software de servidor de grande porte. Os binrios tendem a ser enorme e levou muito tempo para compilar, e da prpria linguagem era muito antiga. Um monte de ideias e mudanas no hardware que surgiram no ltimo par de dcadas no 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 construdo 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 lngua que tem a sensao de uma linguagem dinmica como Python ou Ruby, mas tem o desempenho e a segurana de linguagens como C ou Java. Go procura reinventar programao no mais prtico de formas: a sua no fundamentalmente uma nova linguagem, ele constri e melhora muito na sintaxe estilo C # / Java / C existente. Prope interfaces para programao orientada a objetos e goroutines / canais para programao concorrente e paralela. Para aqueles de vocs que esto 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 cabea, o que no pode ser dito de C + + ou Java, a barreira de entrada baixo, em comparao com, por exemplo Scala (a lngua concorrente Java). Go um moderno C. A maioria dos cdigos-exemplos e exerccios fornecidos interagir com o console, que no uma surpresa, j que Go em essncia uma lngua sistemas. Fornece um framework de interface grfica do usurio (GUI), que independente de plataforma uma tarefa enorme. Mas nesta poca a web e seus protocolos esto onipresente, de modo a fornecer uma interface grfica em alguns exemplos e exerccios, vamos utilizar poderosos pacotes http e modelo embora. Toda linguagem contm novas caractersticas e omite recurso favorito de algum. Go foi projetado com um olho na felicidade de programao, a velocidade de compilao, ortogonalidade dos conceitos, e da necessidade de oferecer suporte a recursos como a concorrncia e coleta de lixo. O seu recurso favorito pode estar faltando porque ele no se encaixa, porque afeta a velocidade de compilao ou clareza de
Origens e evoluo
Ano da nascimento do Go era de 2007, e no ano de seu lanamento pblico foi de 2009. O projeto inicial em Go comeou em 21 de setembro de 2007, como um projeto de 20% a tempo parcial em Google Inc. Sendo um projeto de cdigo aberto, a partir de ento uma comunidade crescendo rapidamente formouse o que acelerou muito o desenvolvimento e uso da lngua. Desde o seu lanamento, mais de 200 colaboradores no-Google ter apresentado mais de 1000 alteraes ao ncleo Go, ao longo dos ltimos 18 meses, 150 desenvolvedores contriburam novo cdigo. Esta uma das maiores equipes de cdigo aberto do mundo. Go iniciou um monte de agitao quando foi lanado publicamente e em 08 de janeiro de 2010 Go foi declarado "lngua do ano 2009 'pelo Tiobe (ranking mundial popularidade de linguagens de programao). Neste ranking que atingiu o seu valor mximo em fevereiro de 2010. Ano Vencedor 2010 Python 2009 Go 2008 C 2007 Python 2006 Rubi 2005 Java 2004 PHP 2003, C + + Go Linguagem de Programao do ano 2009 no Tiobe
Desde maio de 2010 Go usado na produo do Google para a infraestrutura de back -end, por exemplo, programas de escrita para a administrao de ambientes complexos. Isso prova que o Google quer investir nela, e que a lngua a produo digna. O site principal http:/ /golang.org/ o site oficial do projeto, onde voc tambm pode escrever e compilar seus cdigos Go on-line, para aprendizado. 1.2 Principais caractersticas, contexto e as razes para o desenvolvimento de uma nova linguagem 1.2.1 Lnguas que influenciaram Go Go uma linguagem projetado a partir do zero, como um "C para o sculo 21". Pertence -famlia C, como C + +, Java e C #, e inspirado em muitas lnguas criadas e usadas por seus designers. Houve contribuio significativa da famlia Pascal / Modula / Oberon e de Python. Por seu mecanismo de concorrncia que tem por base a experincia adquirida com Limbo e Newsqueak, que se foram inspirados pela teoria CSP de Tony Hoare (comunicao de processos sequenciais), o que essencialmente o mesmo mecanismo usado pela linguagem Erlang. uma linguagem completamente open-source, distribudo com uma licena BSD, por isso pode ser usado por todos, mesmo para fins comerciais sem uma taxa, e pode at mesmo ser alterado por outros. A semelhana com o C-sintaxe foi mantida de modo a ser imediatamente familiarizado com a maioria dos desenvolvedores, porm comparando com C / C + + a sintaxe bastante simplificado e tornado mais conciso e limpo. A figura a seguir mostra algumas das influncias: 1.2.2 Por uma nova linguagem?
A meta principal era combinar a eficcia, rapidez e segurana de uma linguagem fortemente e compilado estaticamente com a facilidade de programao de uma linguagem dinmica, de modo a tornar a programao mais divertido novamente. Assim, a linguagem de tipo seguro (tipy safe), e tambm a memria de segura (memory safe):
Go tenta reduzir a digitao, desordem e complexidade na codificao atravs de uma quantidade mnima de palavras-chave (25). Juntamente com a sintaxe limpa, regular e concisa, este aumenta a velocidade de compilao, porque as palavras -chave pode ser analisado sem uma tabela de smbolos. Estes aspectos reduzir o nmero de linhas de cdigo necessrias, mesmo em comparao com Java. Go tem uma abordagem minimalista: tende a haver apenas uma ou duas formas de fazer as coisas, para que a leitura de cdigo de outros personagens geralmente muito fcil, ns sabemos legibilidade do cdigo de extrema importncia para a engenharia de software. Os conceitos de design da linguagem Go no fica no caminho do outro, eles no somam complexidade uns aos outros, ou seja, eles so ortogonais. essencialmente tem uma estrutura de linguagem processual e imperativo, construdo com a concorrncia em mente. Tem uma abordagem diferente de orientao a objetos, diferente de Java e C + +, porque ele no tem o conceito de classes e herana. 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 hbrida. Orientao a objetos considerada "pesada", levando ao desenvolvimento muitas vezes complicado construir grandes hierarquias de tipo, e assim no compatvel com a meta de velocidade da linguagem Go. As funes so o bloco de construo bsico em Go, e seu uso muito verstil, apresentando aspectos fundamentais de uma linguagem funcional.
ORIENTAO A OBJETOS EM GO
Go uma linguagem orientada a objeto? Sim e no. Embora Go tem tipos e mtodos e permite um estilo orientado a objetos de programao, no h hierarquia de tipos. O conceito de "Interface" no Go oferece uma abordagem diferente, que ns acreditamos que fcil de usar e de certa forma mais geral. Um tipo Go satisfaz uma interface atravs da implementao dos mtodos dessa interface, nada mais. Essa propriedade permite que interfaces para ser definido e usado sem ter que modificar o cdigo existente. Ele permite que um tipo de digitao estrutural que promove a separao de interesses e melhora cdigo reuso, e torna mais fcil para construir sobre os padres que emergem como o cdigo se desenvolve. A semntica de interfaces uma das principais razes para a agilidade e sensao de leveza. Go no suporta sobrecarga de mtodos e operadores. Mtodo envio simplificada se no precisa fazer tipo de correspondncia tambm. A experincia com outros idiomas nos disse que ter uma variedade de mtodos com o mesmo nome mas assinaturas diferentes ocasionalmente til, mas que ele tambm poderia ser confuso e frgil na prtica. Correspondncia apenas pelo nome e exigindo consistncia nos tipos era uma deciso importante simplificao no sistema de tipo de Go. Em relao a sobrecarga de operador, parece mais uma convenincia do que uma exigncia absoluta. Mais uma vez, o que mais simples, sem ele. H tambm maneiras de incorporar tipos em outros tipos de fornecer algo anlogo, mas no idntico a subclasse. Alm disso, os mtodos de Go so mais gerais do que em C + + ou Java: eles podem ser definidos para qualquer tipo de dados, mesmo tipos internos, como a plancie, inteiros "desembalados". Eles no esto restreitos a estruturas (classes). Alm 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 trs aspectos importantes das lnguas orientadas a objetos so encapsulamento, herana e polimorfismo, como eles esto previstos no Go? i) Encapsulation (ocultamento de dados): por definio geral encapsulamento consiste na separao 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 mtodos que alteram estes estados ao contrrio de outras linguagens OO, onde h 4 ou mais-nveis de acesso, Go simplifica isso para apenas 2 (o famoso Public-privat do Go): 1) escopo do pacote: "objeto" s conhecida em seu prprio pacote, como? ele comea com uma letra minscula (privado). 2) exportado: "objeto" visvel do lado de fora de seu pacote, como? ele comea com uma letra maiscula (Publico) Um tipo s pode ter mtodos definidos em seu prprio pacote. ii) Herana: como conceito geral herana significa o mecanismo pelo qual uma classe (subclasse) pode estender outra classe (superclasse), aproveitando seus comportamentos (mtodos) e estados possveis atributos. H herana mltipla quando uma subclasse possui mais de uma superclasse. Um
Usos da linguagem
Go foi originalmente concebido como uma linguagem de programao de sistemas, para ser usado no servidores web mundial do Google, arquitetura de armazenamento e assim por diante. Para certos domnios, como sistemas distribudos de alto desempenho Go j provou ser uma linguagem mais produtiva do que a maioria dos outros e fazendo concorrncia macia fcil, por isso deve ser um bom projeto para desenvolvimento em servidores. Go usados internamente no Google para dever cada vez mais pesado de aplicaes distribudas. Mas tambm uma linguagem de programao geral, e muito til para a resoluo de problemas de processamento de texto, fazendo interfaces ou aplicativos no mesmo script-like. No entanto o uso de Go no adequado para software em tempo real por causa da coleta de lixo e de alocao de memria automtica. Uma srie de caractersticas que podem ser encontrados na maioria dos lnguas orientadas a objeto modernas esto em falta no Go, alguns deles ainda pode ser implementado no futuro. - Sem funo ou sobrecarga de operadores: isso para simplificar o design. - No h converses implcitas por design, para evitar os muitos erros e confuses decorrentes de C / C++ - No h classes e tipo de herana: Go tem uma outra abordagem para o design orientado a objeto. - Nenhum tipo de variante: quase a mesma funcionalidade realizado atravs de interfaces. - Sem cdigo de carregamento dinmico - No h bibliotecas dinmicas - No h genricos - Sem excees (embora recover/panic um conceito similar) - No h assertions - No h variveis imutveis
MUDANAS DE GO EM RELAO AO C
Embora ele no 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 padres mais comuns em linguagens dinmicas, Go inclui a mudana de C destinados a manter cdigo conciso e legvel. O programador no precisa especificar os tipos de expresses, semicolons no estreitol das linhas no so necessrios. Funes podem retornar valores mltiplos, nomeado, e retornando a um resultado. Possuem uma maneira padro de lidar com erros, depois de inicialmente omitindo excees, a lngua acrescentou o panic / recover mecanismo, mas ele serve apenas em raras circunstncias. As Estruturas complexas podem ser construdas durante a inicializao e as questes de ordenao
BBC
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 distribuio principal. Go est disponvel na fonte e em forma binria nessas plataformas amd64, 386, ARM. A portabilidade do Go-cdigo entre Sistemas excelente: basta copiar o cdigo-fonte para o outro Sistema e compilar. Os compiladores e linkers Go so escritos em C e produzir cdigo nativo, de modo que um compilador diferente necessrio para cada combinao 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. Compilao mais lento, mas o cdigo nativo gerado mais rpido. Este tambm oferece algumas interoperabilidades com C. As extenses de arquivo e pacotes para cdigo fonte Go . go e arquivos C terminam em c e arquivos de montagem em s. Um programa executvel em Windows .exe. A arquitetura Go-compilador permite compilao cruzada: voc pode compilar em uma mquina (= o anfitrio), que tem outras caractersticas (sistema operacional, processador) do que a mquina de destino. Instalando Go em um sistema Linux Procure por golang na central de programas do ubuntu o modo mais fcil de instalar, mas voc pode compilar a partir do cdigo fonte se quiser. A ferramenta Go escrito em C, ento para o processo de construo que voc precisa desses programas: GCC,
2.7 O tempo de execuo Go Embora o compilador gera cdigo executvel nativo, esse cdigo executado dentro de um tempo de execuo (o cdigo dessa ferramenta est contida no tempo de execuo do pacote). Este tempo de execuo um pouco comparvel com as mquinas virtuais usados pelo Java e. NET. Ele responsvel pelo gerenciamento de alocao de memria e coleta de lixo, a movimentao de pilha, goroutines, canais, slices, mapas, reflexo e muito mais. Coletor de lixo: Ter uma linguagem de coleta de lixo no significa que voc pode ignorar as questes de alocao de memria: alocao e desalocao de memria tambm usa cpu -recursos. Arquivos executveis so muito maiores em tamanho binrio do que os arquivos de cdigo fonte, este
Um Go Makefile tambm 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 atravs de MinGW, que ainda lhe d a possibilidade de construo 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 contrao de "minimalista GNU for Windows", um ambiente de desenvolvimento minimalista para aplicaes nativas do Microsoft Windows, que necessrio para rodar alguns aplicativos prprios do Linux no Windows. MinGW fornece um conjunto de ferramentas Opensource de programao completa, que adequado para o desenvolvimento de aplicaes nativas MS -Windows, e que no depende de quaisquer 3 -party CRuntime DLLs. (Ele faz depender de uma srie de DLLs fornecido pela prpria Microsoft, como componentes do sistema operacional; mais notveis entre estes MSVCRT.DLL, a biblioteca de tempo de execuo Microsoft C Alm disso, os aplicativos segmentados deve ser fornecido com uma DLL apoio fio distribudo gratuitamente, fornecida como parte do prprio MinGW). Compiladores MinGW fornece acesso funcionalidade de tempo de execuo do Microsoft C e alguns tempos de execuo especficos do idioma. MinGW, sendo minimalista, no faz, e nunca ser, tentativa de fornecer um ambiente de execuo POSIX para a implantao de aplicativos POSIX em MS -Windows. Se voc quer a implantao 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 tambm est disponvel 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 implantao em MS-Windows Um wrapper GUI (mingw-get-inst) para a instalao de linha de comando MSYS, uma contrao de "sistema mnimo", um sistema de linha de comando intrprete 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 aplicaes Opensource para a plataforma MS-Windows; um garfo leve de Cygwin- 1.3, que inclui uma pequena seleo de ferramentas Unix, escolhido para facilitar esse objetivo.
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 discusso mais detalhada de LiteIDE e GoClipse.
Golang LiteIDE
A verso 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),
Os autores no queria discusses interminveis sobre estilo de cdigo para linguagem, discusses que, no passado, subiram para muitas linguagens de programao e que eram certamente de uma forma um desperdcio de tempo de desenvolvimento precioso. Ento eles fizeram uma ferramenta: gofmt. Que impe a oficial, formatao de cdigo padro e estilo no cdigo -fonte Go. uma ferramenta de reescrita nvel de sintaxe, uma forma simples de refatorao: use gofmt em seu programa Go antes de compilar ou verificar. Embora no sem debate, o uso de gofmt e como consequncia, a sintaxe da liberdade que voc tem que desistir de certamente ter grandes vantagens em fazer cdigo uniforme e melhor legvel e, portanto, facilita a tarefa cognitiva de compreender Go -cdigo estrangeiraa. A maioria dos editores t -lo construdo dentro para recuo de diferentes nveis no cdigo no rirrosa 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. No h referncias oficiais, mas as comparaes experimentais regulares entre lnguas mostram uma pista muito boa performance. Uma declarao mais realista que Go 20% mais lento do que C + +. Isso coloca os programas Go conservador duas vezes mais rpido e exige 70% menos memria quando comparado a um Java equivalente ou aplicao Scala. Em muitos casos essa diferena Irrelevante, mas para uma empresa como a Google, com milhares de servidores potenciais melhorias de eficincia so certamente vale a pena o investimento. Os atuais linguagens populares executadas em uma mquina virtuais: JVM para Java e Scala, NET CLR para C #, etc. Mesmo com as melhorias enormes em mquinas virtuais, JIT -compiladores e intrpretes de linguagem de script (Ruby, Python, Perl, Javascript) ningum 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 rpido do que qualquer lngua que no de tipagem esttica e compilada, e muito mais eficiente de memria. Alguns resultados de benchmarking: (1) Comparando Go e Python em aplicaes de servidor web simples, medidos em transaes / s: O pacote http Go nativa 7-8 x mais rpido do que web.py, web.go ligeiramente menos eficaz com uma proporo de 6-7 em comparao com web.py. O tornado assncrona 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) Vo , em mdia, 25 x mais rpido do que o Python 3, utiliza 1/3 da memria, com o nmero de linhas de cdigo quase igual ao dobro. (3) O artir de Robert Hundt comparando C + +, Java, Go, e Scala, e, a reao da equipe Go: algumas concluses tendo em conta a aestreitoo do Go -time: - Verses Scala e Go so significativamente mais compacto (menos linhas de cdigo) do que o verboso C + + e Java - Vai compila mais rpido do que outros, 5 -6x comparando para Java e C + +, 10x em comparao com Scala - Go tem o maior tamanho de binrio (cada executvel contm o tempo de execuo)
Unicode UTF-8
Unicode um padro 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 internacionalizao e localizao de programas de computador. O padro foi implementado em vrias tecnologias recentes, incluindo XML, Java e sistemas operacionais modernos. O Unicode possui o objetivo explcito de transcender as limitaes de codificaes de carcter tradicionais. O armazenamento dos cdigos Unicode no processamento de texto apresenta o desafio de a maioria dos programas de computador escritos no mundo ocidental utilizar somente codificaes de 8 bits 1 byte (como o padro ASCII), j que o suporte ao Unicode comeou somente nos ltimos anos. Similarmente, na representao de sistemas de escrita asiticos, o modelo baseado em ASCII de caracteres de 2 bytes no pode mesmo em teoria codificar mais que 32 7688 caracteres e, na prtica, as arquiteturas impem limites ainda menores. Tais limites so insuficientes mesmo s tendo em conta as necessidade de acadmicos da lngua chinesa. Por outro lado, a UTF-8 uma codificao de muito usada, e que maximiza a compatibilidade com ASCII. Utiliza entre um e quatro bytes por cdigo e, sendo compacta para o sistemas latino e compatvel com ASCII nos cdigos at 127, fornece um padro de fato de codificao para a converso de textos para o formato Unicode. usada pelas mais recentes distribuies Linux como uma substituta para codificaes legadas na manipulao de texto. A UTF-8 representa uma forma de otimizar o espao alocado para textos Unicode. Considerando por exemplo um texto escrito em lngua inglesa, percebe -se que raramente so utilizados caracteres fora do escopo do ASCII, isto , os primeiros 127 cdigos Unicode. Isso significa que se for utilizada uma codificao de largura fixa de 16 bits, o segundo byte de cada carcter muito provavelmente estar vazio, nulo, inutilizado. Para arquivos grandes a sobrecarga desse espao intil alocado passa a ser relevante. Tendo uma largura variada, o UTF -8 define que caracteres ASCII so representados com somente um byte. Alm de otimizar o espao alocado no caso de caracteres ASCII, isso garante a paridade entre ASCII e UTF-8, facilitando a traduo de texto ASCII legado para o Unicode. Uma propriedade adicional do UTF-8 diz respeito ao truncamento de cadeias de caracteres Unicode. Alguns cdigos 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 tambm para o armazenamento (apesar de muitos textos ainda estarem armazenados em codificaes legadas).
Notao A sintaxe especificado usando estendida Backus-Naur Form (EBNF): Produo = production_name "=" [expresso] "." . Expresso = {Alternativa "|" Alternativa}. Alternativa = Term { } Term. Termo = production_name | smbolo ["..." smbolo] | Grupo | Opo | Repetio. Grupo = "(" Expresso ")". Opo = "[" Expresso"]". Repetio = "{" Expresso"}". Produes so expresses construdas a partir de termos e os seguintes operadores, no aumento da precedncia: | Alternncia ( ) Agrupamento [ ] Opo (0 ou 1 vezes) { } Repetio (0 a n vezes)
Blocos
Um bloco uma sequncia possivelmente vazio de declaraes e instrues dentro correspondentes suportes de chave. Block = "{" StatementList "}". StatementList = { Statement ";"}. Alm de blocos explcitos no cdigo-fonte, h blocos implcitas:
1. 2. 3. 4. 5.
O bloco universo engloba tudo Go texto original. Cada pacote tem um bloco de pacote contendo todas Go texto de origem para esse pacote. Cada arquivo tem um bloco de arquivo que contm todas Go texto de origem no arquivo. Cada "for" , "if" , e "switch" declarao considerado em seu prprio bloco implcito. Cada clusula de um "switch" ou "select" Declarao age como um bloco implcito. Blocos ninho e influncia de escopo.
Declaraes e escopo A declarao se liga um no-Nulo identificador para uma constante, tipo, varivel, funo, rtulo 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
O cdigo-fonte armazenado em.go arquivos, esses nomes consistem em minsculas -letras, como scanner.go Se o nome composto de vrias partes, no so separadas por sublinhados _, como scanner_test.go Os nomes de arquivo no pode conter espaos ou outros caracteres especiais. O arquivo de origem contm as linhas de cdigo, que de comprimento no tm limite intrnseco. Quase todas as coisas em Go-cdigo tem um nome ou um identificador. Como todas as lnguas no Cfamlia, sensvel a maisculas. Identificadores vlidos comear com uma letra (a letra cada letra Unicode UTF-8 ou _), e seguido por 0 ou mais letras ou dgitos Unicode, como: X56, grupo1, _x23, i, 12 No so identificadores vlidos: 1ab (Comea com dgito), caso (= palavra-chave no Go), a + b (operadores no so permitidos) O _ em si um identificador especial, chamado de identificador em branco. Ele pode ser usado em declaraes ou atribuies de variveis como qualquer outro identificador (e qualquer tipo pode ser atribudo a ele), mas o seu valor descartado, para que ele no pode mais ser usado no cdigo que se segue. s vezes possvel que as variveis, tipos ou funes no tm nome, porque no realmente necessrio naquele momento no cdigo e at mesmo aumenta a flexibilidade: estes so chamados annimo. Este o conjunto de 25 palavras -chave ou palavras reservadas usadas em Go-cdigo: break case chan const continue default if else fallthrough for func go goto import interface map package range return struct switch type var select defer
Ele mantido deliberadamente pequena para simplificar o cdigo -anlise, o primeiro passo no processo de compilao. A chave no pode ser utilizado como um identificador. Alm das palavras-chave GO tem um conjunto de 36 identificadores predeclarados: estes contm os nomes de tipos elementares e algumas funes internas bsicas, todos estes sero explicados ainda mais nos prximos captulos: append copy int32 print bool false int64 println byte float32 iota real cap float64 len recover
CURSO GRATUITO
Programas consistem de palavras-chave, constantes, variveis, operadores, tipos e funes. Os seguintes delimitadores so usados: parnteses ( ), colchetes [ ] e chaves { }. Os seguintes caracteres de pontuao.,,, E ...so utilizados. Cdigo estruturado em declaraes. Uma declarao no precisa terminar com um ponto e vrgula (como imposta no C e famlia). O compilador Vai tem um modo de inserir automaticamente vrgulas no estreitol de declaraes. No entanto, se vrias instrues so escritas em uma nica linha (uma prtica que no incentivado por razes de legibilidade), eles devem ser separados por ponto e vrgula;
Personagens
Os seguintes termos so usados para designar classes especficas de caracteres Unicode: letter unicode_letter | "_" . decimal_digit "0" ... "9" . octal_digit "0" ... "7" . hex_digit "0" ... "9" | "A" ... "F" | "a" ... "f" .
As seguintes sequncias de caracteres representam especiais: + & += &= && == != | -= |= || < <= * ^ *= ^= <> >= / << /= <<= ++ = := % >> %= >>= ! &^ &^= Pacotes, importao e visibilidade
Os pacotes so uma forma de estruturar cdigo: um programa construdo como um "pacote" (muitas vezes abreviado como pkg), que podem utilizar as instalaes de outros pacotes. Cada go-arquivo pertence a um pacote (como uma biblioteca ou espao de nomes em outras lnguas). Muitos arquivos diferentes. Go pode pertencem a um nico pacote, por isso o nome do arquivo e nome do pacote no so geralmente os mesmos. O pacote para o qual o arquivo de cdigo pertence deve ser indicado na primeira linha, por exemplo: package main. Um executvel autnomo pertence ao package main. Cada aplicao Go contm um pacote chamado principal. Uma aplicao pode ser composta de pacotes diferentes, mas mesmo se voc usar s package main, voc no tem que encher todo o cdigo em um arquivo grande: voc pode fazer uma srie de arquivos menores cada um com pacote principais como primeira linha de cdigo. Se voc compilar um arquivo de origem com um nome de pacote que no seja principal, como pack1, o arquivo objeto armazenado em pack1.a; um nome de pacote escrito em letras minsculas. Quando o identificador (de uma constante, varivel, tipo, funo, campo de struct ...) comea com uma letra maiscula, como Grupo1, em seguida, o "objeto" com este identificador visvel no cdigo fora do pacote (assim disponvel para o cliente -programas, dos importadores "do pacote), diz a ser exportado (como Pblico em linguagens OO). Identificadores que comeam com uma letra minscula no so visveis fora do pacote, mas eles so visveis e utilizveis nos todo o pacote (como privado). (Letras maisculas pode vir de toda a gama Unicode, como o grego, no apenas letras ASCII so permitidos.) Assim, a importao de um pacote d apenas o acesso aos objetos exportados nesse pacote. Suponha que temos uma varivel ou funo chamada Thing (comea com T por isso exportada) em
CURSO GRATUITO
um pack1 pacote, ento quando pack1 importado no pacote atual, coisa pode ser chamado com a notao de ponto habitual de OO-lnguas : pack1.Thing (. pack1 A necessrio!) Assim, os pacotes tambm servem como espaos de nomes e pode ajudar a evitar name -choques (nome-conflitos): variveis com o mesmo nome em dois pacotes so diferenciados por seu nome do pacote, como: pack1.Thing e pack2.Thing Um pacote pode, se o considerar til (para encurtar, conflitos de nome ...), tambm ser dado um outro nome (um apelido), como: fm import "fmt". O alias usado no cdigo a seguir: package main import fm fmt / / alias3 func main( ) { fm.Println(hello, world) } Observao: Importao de um pacote que no utilizado no resto do cdigo uma compilao de erros (por exemplo: importado e no utilizado: os). Isto segue a Go-lema: "nenhum cdigo desnecessrio! " Declaraes de nvel de pacote e inicializaes: Aps a declarao de importao 0 ou mais constantes (const), variveis (var) e tipos (tipo) podem ser declarados, que so global (tem escopo do pacote) e so conhecidos em todas as funes no cdigo (como c e v em gotemplate, e que seguida por uma ou mais funes (funes).
Funes
A declarao da funo mais simples tem o formato: func functionName ( ) Entre os parnteses no obrigatrios ( ), um ou mais parmetros (separados por,) pode ser dado como entrada para a funo. Aps o nome de cada varivel de parmetro deve vir seu tipo. A funo principal de partida necessria (geralmente a primeira funo), caso contrrio o erro de compilao undefined: main.main ocorre. main no tem parmetros e nenhum tipo de retorno (ao contrrio do C-famlia), caso contrrio, voc recebe o erro de compilao: funo principal no deve ter argumentos e nenhum resultado valores de retorno. Quando o programa executado, depois de inicializaes a primeira funo 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 cdigo em funes (o corpo) colocada entre chaves: { } O primeiro {deve estar na mesma linha que a funo de declarao: esta imposta pelo compilador e gofmt (compilao de erros: erro de sintaxe: ponto e vrgula inesperado ou nova linha antes de {). (Isto acontece porque o compilador produz ento funo principal ( ), o que um erro.) A ltima} posicionado aps a funo do cdigo da coluna abaixo funo; 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 { } so usados (por exemplo: se, etc.) Assim, esquematicamente, uma funo geral se parece com: func functionName (parameter_list) (return_value_list) { ...
CURSO GRATUITO
} Onde parameter_list da forma (param1 type1, param2 type2, ) e return_value_list da forma (ret1 type1, ret2 type2, ) Nomes de funes s comear com uma letra maiscula quando a funo tem que ser usado fora do pacote, em seguida, eles seguem PascalCasing, caso contrrio, eles seguem camelCasing: cada novo wordin o nome comea com uma letra maiscula. A linha: fmt.Println (hello, world) chama a funo println do fmt pacote, que imprime a string de parmetro para o console, seguido por uma nova linha de caracteres \ n. O mesmo resultado pode ser obtido com fmt.Print (hello, world\n) Estas funes de impresso e println tambm pode ser aplicado a variveis, como em: fmt.Println (arr), eles usam o formato de sada padro para o arr varivel. Impresso de uma cadeia ou uma varivel pode ser feito ainda mais simples com a impresso e println funes predefinidas: print ("ABC") ou println ("ABC"), ou (com uma varivel i): System.out.println (i) Estas so apenas para ser usado na fase de depurao, quando a implantao de um programa de substitu-los por seus parentes FMT. A execuo de uma funo interrompido quando o fechamento} atingido ou quando uma instruo de retorno encontrado, a execuo do programa continua com a linha aps a chamada da funo. O programa sai normalmente com o cdigo 0 (Programa encerrado com o cdigo 0), um programa que termina de forma anormal sai com outro cdigo inteiro como 1, o que pode ser usado para testar a execuo exitosa de ele programa a partir de um script.
Comentrios
package main import fmt / / pacote para implementao formatado I / O. func main( ) { fmt.Printf( ; or \n) } Isso ilustra o carter internacional, imprimindo ; ou , e tambm os caracteres utilizados para indicar um comentrio. Existem duas formas de comentrios: 1. Comentrios de linha comea com a sequncia de caracteres / / e pare no fim da linha. Um comentrio linha funciona como uma nova linha. 2. Comentrios gerais comeam com a sequncia de caracteres / * e continuar atravs da sequncia de caracteres * / . Um comentrio geral que contm um ou mais quebras de linha funciona como uma nova linha, caso contrrio, ele age como um espao. Os comentrios no fazem ninho. Cada pacote deve ter um comentrio pacote, um bloco de comentrio imediatamente anterior instruo do pacote, introduzindo o pacote e fornecer informaes relevantes para a embalagem e sua funcionalidade como um todo. A embalagem pode ser repartido por vrios ficheiros, mas o comentrio precisa de estar em apenas um deles. Exemplo: / / Super-homem pacote implementa mtodos para salvar o mundo. // / / A experincia tem mostrado que um pequeno nmero de processos pode provar / / til ao tentar salvar o mundo. Quase todo tipo de nvel superior, const, var e func, e, certamente, todos os nomes exportados em um programa deve ter um comentrio. Este comentrio (chamado um comentrio doc) aparece na linha anterior, e para uma funo Abcd deve comear com: "ABCD ...". Pacote super-homem Exemplo:
CURSO GRATUITO
/ / EnterOrbit provoca Superman voar em rbita baixa da Terra, uma posio / / Que apresenta vrias possibilidades de planeta salvao. func enterOrbit( ) error { ... } Tipos
Variveis (como constantes) contm dados, e os dados podem ser de diferentes tipos de dados ou tipos para breve. A declarao de uma varivel com var inicializa automaticamente para o valor de zero definido para seu tipo type.A define o conjunto de valores e o conjunto de operaes que podem ocorrer nesses valores. Tipos podem ser primria (ou primitiva), como int, float, bool, string ou estruturados (ou composta), como struct, variveis, slices, maps, canais e interfaces, que apenas descrevem o comportamento de um tipo. Um tipo estruturado que no tem valor real (ainda) tem o valor nulo, que tambm o valor padro para estes tipos (em Objective-C que tambm chamado de zero, em Java, nulo, em C e C + + NULL ou 0). No h hierarquia de tipos. As funes tambm podem ser de um certo tipo, este o tipo da varivel que retornado pela funo. Este tipo escrito aps o nome da funo e sua lista de parmetros opcionais, como: func FunctionName (a typea, b typeb) typeFunc A varivel var retornou de typeFunc aparece em algum lugar na funo na declarao: return var A funo pode retornar mais de uma varivel, ento os tipos de retorno so indicados separados por vrgula de e rodeado por ( ), como: func FunctionName (a TypeA, b TypeB) (t1 tipo1, tipo2 t2) Exemplo: a funo atoi : func atoi (s string) (i int, err erro) Ento retorno assume a forma: var1, var2 Retorno Isso muitas vezes usado quando o sucesso (true / false) da execuo de uma funo ou o mensagem de erro devolvido juntamente com o valor de retorno (ver vrias atribuies abaixo). Use a palavra-chave para a definio de tipo de seu prprio tipo. Ento voc provavelmente vai querer definir um tipo struct (ver Captulo 10), mas tambm possvel definir um alias para um tipo existente, como em: type IZ int E ento ns podemos declarar variveis como: var a IZ = 5 Dizemos que um tem int como tipo subjacente, o que torna possvel a converso. Se voc tiver mais de um tipo de definir, voc pode usar o formulrio de palavras -chave consignado, como em: type ( IZ int FZ float STR string )
Cada valor deve ter um tipo aps compilao (o compilador deve ser capaz de inferir os tipos de todos os valores):Go uma linguagem de tipagem esttica. Estrutura geral de um programa Go
CURSO GRATUITO
O programa a seguir compila mas no faz nada til, mas demostra a estrutura preferencial para um programa Go. Esta estrutura no necessrio, o compilador no se importa se main ( ) ou as declaraes de variveis vm por ltimo, mas uma estrutura uniforme torna o cdigo Go melhor leitura de cima para baixo. Todas as estruturas sero explicados neste e nos prximos captulos, mas as ideias gerais so os seguintes: Aps a importao: declarar constantes, variveis e os tipos Em seguida, vem a funo init ( ), se houver qualquer: uma funo especial que cada pacote pode conter e que executado em primeiro lugar. Em seguida, vem a funo main ( ) (somente no package main) Em seguida vm do resto das funes, os mtodos nos primeiros tipos, ou as funes de modo que eles so chamados de main ( ) em diante, ou os mtodos e funes alfabeticamente se o nmero de funes alta. gotemplate.go: package main import ( fmt ) const c = C var v int = 5 type 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 execuo (incio do programa) de um aplicativo Go a seguinte: (1) todos os pacotes no package main so 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 variveis so avaliadas, e init ( ) se ele contm essa funo. (4) por fim no package main o mesmo acontece, e, em seguida, main ( ) comea a executar.
Converses
Se necessrio e possvel um valor pode ser convertido (elenco, coagido) em um valor de outro tipo. Go nunca implcito para converso, isso deve ser feito de forma explcita, com a sintaxe como uma chamada de funo (um tipo usado aqui como uma espcie de funo): valueOfTypeB = typeB (valueOfTypeA) Exemplos: a: = 5.0
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 converso 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 converso impossvel e que o compilador detecta isso, um erro de compilao dada, caso contrrio, ocorre um erro de execuo. As variveis com o mesmo tipo de base podem ser convertidos um no outro: var a IZ = 5 c := int(a) d := IZ(c)
Ter um cdigo Limpo, legvel e simples so um dos principais objetivos para o desenvolvimento Go. gofmt impe o estilo de cdigo. Os nomes das coisas em Go deve ser curto, conciso, evocativa. Nomes longos com tampas mistos e sublinhados que so muitas vezes vistos, por exemplo em Java ou cdigo Python muitas vezes dificulta a legibilidade. Os nomes no devem conter a indicao do pacote: a qualificao com o nome do pacote suficiente. Um mtodo ou funo que retorna um objeto apontado como um substantivo, no obter necessria. Para alterar um objeto, use SetName. Se necessrio, Go usa MixedCaps ou mixedCaps ao invs de escrever ressalta nomes multiword. Constantes
A const constante contm dados imutveis. 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 explcita digitao: const b string = "abc" Exemplo digitao implcita: 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 contrrio formulada: uma constante sem tipo leva o tipo necessrio para o seu contexto): var n int f (n + 5) / / constante numrica sem tipo "5" torna-se do tipo int Constantes devem ser avaliadas em tempo de compilao, um const pode ser definida como um clculo, mas todos os valores necessrios para o clculo deve estar disponvel em tempo de compilao. Ento, isso ok: c1 const = 2/3 Este no : const c2 = getNumber ( ) / / D o erro de compilao: getNumber ( ), utilizado como valor Constantes numricas no tm tamanho ou sinal, pode ser de alta preciso arbitrria e no fazer nenhum overflow: const Ln2= 0.693147180559945309417232121458\
CURSO GRATUITO
176568075500134360255254120680009 const Log2E= 1/Ln2 const Billion = 1e9 const hardEight = (1 << 100) >> 97 / / este um recproco preciso / / constante flutuante
Como demonstrado \ pode ser utilizado como um carcter de continuao de uma forma constante. Em contraste com as variveis numricas de diferentes tipos, com constantes que voc no tem que se preocupar com converses: so como nmeros ideais. Constantes podem transbordar apenas quando eles so designados para uma varivel numrica com muito pouca preciso para representar o valor, isso resulta em um erro de compilao. Atribuio mltipla 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 = 0 Feminino = 1 Masculino = 2 ) Desconhecido, Feminino, Masculino j esto 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 tambm pode ser usado em uma expresso, como iota + 50. Um novo bloco de const ou declarao inicializa iota volta para 0. Naturalmente, o valor de uma constante no pode alterar -se durante a execuo do programa, pois isso impedido por um erro do compilador: no possvel 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
CURSO GRATUITO
Thursday Friday Saturday ) Voc pode dar a enumerao um nome de tipo, como neste exemplo: type Color int const ( RED Color = iota ORANGE YELLOW GREEN BLUE INDIR VIOLET )
Observao: Existe uma conveno para citar identificadores constantes com todas as letras maisculas, como: const INCHTOwCM = 2.54, o que melhora a legibilidade e pode ser usado, desde que ele no est em conflito com a Regra de visibilidade.
Variveis
Vocs sabem que os computadores possuem CPU e memria, certo? A CPU (Unidade Central de Processamento) responsvel pelo controle e processamento dos clculos matemticos e das resolues de expresses lgicas. Todavia, os dados que so usados num processamento precisam ser armazenados em algum lugar este lugar a memria principal. Ela funciona como um armrio que guarda nossos pertences. Todavia, como um armrio, no podemos simplesmente Go guardando nossos pertences sem nenhuma arrumao. Para isso, existem caixas na memria (posies de memria), que nos permitem organizar essas informaes. Essas caixas, conceitualmente recebem nomes e so conhecidas como variveis. Toda varivel necessita ser declarada, ou seja, reserva-se um local da memria informando que tipo de dados residiro ali. A forma geral para declarar uma varivel usa em Go a palavra -chave var: var identifier type Importante notar que o tipo escrito aps o identificador da varivel, ao contrrio do que qualquer outra linguagem de programao. Por que os designers Go escolheu para esta conveno? Primeiro ele remove uma certa ambiguidade que pode existir em declaraes C, por exemplo, por escrito int* a, b; Apenas um um ponteiro e b no . 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 *int Em segundo lugar, l bem da esquerda para a direita e assim mais fcil de entender. Alguns exemplos: var a int var b bool var str string Que tambm pode ser escrito como: var ( a int b bool
CURSO GRATUITO
str string ) Este formulrio utilizado, principalmente, para declarar variveis globais. Quando uma varivel declarada contm automaticamente o padro 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 memria em Go inicializado. A nomeao de identificadores para variveis segue as regras camelCasing (comear com uma pequena carta, a cada nova parte da palavra comea com uma letra maiscula), como: numShips, startDate Mas se a varivel tem de ser exportada, deve comear com um capital carta. Uma varivel (constante, o tipo de funo) conhecida apenas num determinado intervalo de programa, chamado o mbito. Variveis etc. declarada fora de qualquer funo (em outras palavras, a nvel superior) tm escopo global (ou pacote): eles so visveis e disponveis em todos os arquivos de origem do pacote. Variveis declaradas em uma funo tem escopo local: eles s so conhecidos nessa funo, o mesmo vale para os parmetros e voltar -variveis. No decorrer do livro vamos encontrar construes de controle, como se, e para, uma varivel definida dentro de uma tal construo s conhecido dentro desse construto (construo de escopo). Principalmente voc pode pensar em um mbito que o bloco de cdigo (cercado por { }) em que a varivel declarada. Embora identificadores tm de ser nicos, um identificador declarado em um bloco pode ser declarado novamente em um bloco interno: neste bloco (mas s l) a varivel redeclarado tem prioridade e sombras a varivel externa com o mesmo nome, se cuidados utilizado deve ser tomado para evitar erros sutis. Variveis podem obter o seu valor (que chamado de atribuio e usa o operador de atribuio =) em tempo de compilao, mas, naturalmente, um valor tambm pode ser calculado ou alterados durante a execuo. Exemplos: a = 15 b = false Em geral, uma varivel b s pode ser atribudo a uma varivel como um em que a = b, quando a e b so do mesmo tipo. Declarao e atribuio (inicializao) pode, naturalmente, ser combinadas, no formato geral: Exemplos: var identifier [type] = value var a int = 15 var i = 5 var b bool = false var str string = "Go diz Ol para o mundo!" Mas o Go-compilador inteligente o suficiente para obter o tipo de uma varivel a partir de seu valor (de forma dinmica, tambm chamada de tipo automtico inferncia, um pouco como nas linguagens de script Python e Ruby, mas isso acontece em tempo de execuo), ento as seguintes formas (omitindo o tipo) tambm esto corretas: var a = 15 var 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
CURSO GRATUITO
) Ele ainda pode ser til incluir o tipo de informao no caso em que voc deseja que a varivel a ser digitado algo diferente do que seria se inferir, como em: var n int64 = 2 No entanto uma expresso como uma var no correto, porque o compilador no tem nenhuma pista sobre o tipo de um arquivo. Variveis tambm podem ser expresses computadas em tempo de execuo, tais como: var ( HOME = os.getenv ("HOME") USER = os.getenv ("USER") GOROOT = os.getenv ("GOROOT") ) A sintaxe var usado principalmente em um nvel pacote global, em funes que ele substitudo pela sintaxe declarao curta : = Aqui est um exemplo de um programa que mostra o sistema operacional em que ele executado. Ele tem uma varivel local string ficando o seu valor, chamando a funo getenv (que usado para obter ambiente de variveis) a partir do pacote-os.
package main import ( 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 sada pode ser, por exemplo: O sistema operacional : Windows ou Linux A operao, seguido pelo o contedo da varivel de caminho. Aqui Printf usado para formatar a sada de.
Memria em um computador usado em programas como um enorme nmero de caixas (que como vamos chamar-lhes), chamado palavras. Todas as palavras tm o mesmo comprimento de 32 bits (4 bytes) ou 64 bits (8 bytes), de acordo com o processador e sistema operacional, todas as palavras so identificados pelo seu endereo de memria (representado como um nmero hexadecimal). Todas as variveis de tipos elementares (primitivas), como int, float, bool, string, ...so tipos de valor, eles apontam diretamente para o seu valor contido na memria: O endereo de memria da palavra, onde a varivel i armazenado dado por & i, por exemplo, isso pode ser 0xf840000040. Variveis do tipo de valor so cointained na memria stock. O valor real do endereo ser diferente de uma mquina para outra e mesmo em diferentes execues do mesmo programa que cada mquina pode ter uma disposio diferente e de memria, e tambm a localizao onde atribudo poderia ser diferente. Dados mais complexo que geralmente necessita de vrias palavras so tratadas como tipos de referncia. A varivel de tipo de referncia R1 contm o endereo (um nmero) da posio de memria em que o valor de r1 armazenada (ou, pelo menos, a primeira palavra do mesmo). Este endereo que chamado um ponteiro tambm est contido em uma palavra. As palavras diferentes pontos de um tipo de referncia ao poderiam ser endereos sequenciais de
CURSO GRATUITO
memria (o layout de memria est a ser dito de forma contgua), que o armazenamento mais eficiente para a computao, ou as palavras poderiam ser espalhados ao redor, cada um apontando para o outro. Ao atribuir r2 = r1, apenas a referncia (endereo) copiada. Se o valor de r1 modificado, todas as referncias de que o valor (como R1 e R2), em seguida, apontam para o contedo modificado. Os ponteiros de Go so tipos de referncia, bem como slices, maps e canais. As variveis que so mencionados esto armazenados no monto, o qual recolhido o lixo, e que um espao de memria muito maior do que a pilha.
Impresso
A funo printf visvel fora do pacote fmt porque comea com um P, e usado para imprimir a sada 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 sequncia 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 padro geral. O valor (s) vm na mesma ordem das variveis resumiu aps a vrgula, e elas so separadas por vrgula de, se houver mais do que 1.Estes marcadores de posio% preveem um controle muito estreito sobre a formatao. O fmt.Sprintf funo 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 variveis em seus programas. As funes fmt.Print e fmt.Println executar a formatao automtica de seus argumentos, usando o formato de especificador % v, acrescentando espaos entre argumentos e esta ltima uma nova linha no estreitol. Ento fmt.Print (Hello:, 23) produz como sada: Hello:, 23
Com o tipo omitido, a palavra-chave var nas ltimas declaraes do bem suprfluo, para que possamos escrever em Go: a: = 50 ou b: = false Os tipos de a e b (int e bool) Novamente so inferidos pelo compilador. Esta a forma preferida, mas apenas pode ser utilizado dentro de funes, no no mbito do pacote := operador efetivamente faz uma nova varivel, que tambm chamado de declarao de inicializar. Observao: Se depois de as linhas acima no mesmo bloco de cdigo ns declaramos a: = 20, isso no permitido: o compilador d o erro "sem novas variveis no lado esquerdo :=", no entanto a = 20 ok, porque ento o mesmo varivel s recebe um novo valor. Uma varivel de a usado, mas no declarada, d um erro do compilador: undefined: a Declarando uma varivel local, mas no us-lo, um erro do compilador, como varivel a da seguinte: func main( ) { var a string = abc fmt.Println(hello, world) } Gue d o erro: a declared and not used Tambm a definio do valor de um no suficiente, o valor deve ser lido, a fim de contar como um uso, de modo fmt. Println(hello, world, a) remove o erro.
CURSO GRATUITO
No entanto, para as variveis globais isso permitido. Outras formas de encurtamento convenientes so: Vrias declaraes de variveis do mesmo tipo em uma nica linha, como: var a, b, c int Vrias atribuies de variveis em uma nica linha, como: a, b, c = 5, 7, "abc" Isso pressupe que as variveis a, b e c, onde j declarados, se no: a, b, c: = 5, 7, "abc" Os valores a partir do lado direito so atribudos s variveis 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 atribuio paralela ou simultnea. Com duas variveis que pode ser utilizada para realizar uma permuta de valores: a, b = b, a (Isto elimina a necessidade de fazer uma funo swap em Go) O identificador branco _ tambm pode ser utilizado para deitar fora os valores, como o valor de 5: _, b = 5, 7 _ Est em virr uma varivel somente gravao, voc no pode pedir para o seu valor. Ela existe porque uma varivel declarada em Go tambm deve ser utilizado, e s vezes voc no precisa usar todos os valores de retorno de uma funo. A atribuio mltipla tambm usado quando uma funo retorna mais de um valor, como aqui, onde val e um err erro so retornados de Func1: val, err = Func1(var1)
funes init Alm de declarao global com a inicializao, variveis tambm pode ser inicializado em uma init ( ) function. Esta uma funo especial com nome init( ), que no pode ser chamado, mas executado automaticamente antes da funo main( ) no package main ou no incio da importao do pacote que o contm. Cada arquivo de origem pode conter apenas 1 init ( ) de funes. A inicializao sempre nicothreaded e garantias de dependncia de pacotes para a execuo correta. Um uso possvel verificar ou reparar exatido do estado do programa antes do incio da execuo real. package trans import math var Pi float64 func init( ) { Pi = 4 * math.Atan(1) / / init( ) function computes Pi } Na sua init ( ) o Pi varivel inicializada por clculo. O prximo programa importa o pacote trans (que est no mesmo diretrio) e usa Pi: package main import ( fmt ./trans ) var twoPi = 2 * trans.Pi func main( ) { fmt.Printf(2*Pi = %g\n, twoPi) / / 2*Pi = 6.283185307179586 } Uma funo init( ) tambm frequentemente usado quando (por exemplo, para um aplicativo de servidor) um backend( ) goroutine necessria desde o incio da aplicao, como em: func init( ) { / / setup preparations go backend( ) }
CURSO GRATUITO
O QUE UM TIPO
Ao armazenarmos variveis na memria do computador, precisamos dizer que tipo elas so, para que seja reservado o espao adequado, alm de ser dado o trabalho correto a elas. Comearemos com exemplos clssicos na computao para explicar o que um tipo: TIPO INTEIRO: qualquer nmero inteiro, negativo, nulo ou positivo.Ex.: -15, 0, 101 TIPO REAL: qualquer nmero real, negativo, nulo ou positivo. Ex.: -1, -0.5, 0, 5, 9.5
Em Go valores so combinados em conjunto com os operadores em expresses, que so tambm os valores de um determinado tipo. Cada tipo tem seu prprio conjunto definido de operadores, que pode trabalhar com valores desse tipo. Se um operador usado para um tipo para o qual ele no est definida, ocorre um erro do compilador. Um operador unrio trabalha em um valor (postfix), um operador binrio funciona em dois valores ou operandos (infix). Os dois valores para um operador binrio deve ser do mesmo tipo. Go no converter implicitamente o tipo de um valor, se necessrio isso deve ser feito por uma converso explcita: Go se fortemente typed.There h sobrecarga de operador como em C e Java. Uma expresso , por padro, avaliado a partir da esquerda para a direita. H uma precedncia built-in entre os operadores nos dizendo qual o operador em uma expresso tem a maior prioridade, e por isso executado pela primeira vez. Mas o uso de parnteses ( ) em torno de expresso (s) podem alterar esta ordem: uma expresso dentro de ( ) executado sempre em primeiro lugar.
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 comparao, o primeiro operando deve ser atribuvel ao tipo do segundo operando, ou vice versa. Os operadores de igualdade == e != aplicar a operandos que so comparveis. Os operadores de ordenao < , <= , > , e >= aplica a operandos que so ordenados. Estes termos e os resultados das comparaes so definidos da seguinte forma: Os valores booleanos so comparveis. Dois valores booleanos so iguais se eles so ou ambos true ou ambos false. Os valores inteiros so comparveis e ordenada, da maneira usual. Valores de ponto flutuante so comparveis e ordenada, como definido pelo padro IEEE-754. Complex valores so comparveis. Dois valores complexos u e v so iguais se os dois real(u) == real(v) e imag(u) == imag(v) . String valores so comparveis e ordenada, lxico byte-wise. Valores de ponteiro so comparveis. Dois valores de ponteiro so iguais se eles apontam para a mesma varivel, ou se ambos tm valor nil . Os apontadores para distintas de tamanho zero variveis podem ou no ser iguais.
CURSO GRATUITO
chamada para make ou se ambos tm um valor nil . Valores de interface so comparveis. Dois valores de interface so iguais se eles tm idnticas tipos dinmicos e valores dinmicos iguais ou se ambos tm um valor nil . Um valor x do tipo no-interface de X e um valor de t de tipo de interface T so comparveis quando os valores do tipo X so comparveis e X implementa T. Eles so iguais, se t 's tipo dinmico idntico ao X e t 'valor dinmico s igual a x. Struct valores so comparveis, se todos os seus campos so comparveis. Dois valores de struct so iguais se os seus no-correspondentes em branco os campos so iguais. Valores da array so comparveis se os valores do tipo do elemento da array so comparveis. Dois valores de array so iguais se seus elementos correspondentes so iguais. Um exemplo: var aVar = 10 aVar != 5 aVar != 10
Canal valores so comparveis. Dois valores de canal so iguais se eles foram criados pela mesma
Os valores possveis deste tipo so 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 so os mesmos (valores), caso contrrio. Isto supe que eles sejam do mesmo tipo. Exemplo: var Avar = 10 Avar == 5 falso Avar == 10 verdade No-igual operador: != Isto d verdadeiroo se os valores de ambos os lados so diferentes (valores), caso contrrio. Exemplo: var Avar = 10 Avar! = 5 verdade Avar! = 10 falsa Go muito rirroso sobre os valores que podem ser comparados: eles tm que ser do mesmo tipo, ou se eles so interfaces que deve implementar o mesmo tipo de interface. Se um deles uma constante, que deve ser de um tipo compatvel com o outro. Se estas condies no forem satisfeitas, um dos valores foi o primeiro a ser convertido para o tipo do outro. Constantes booleanas e variveis tambm podem ser combinados com operadores lgicos (e no, e, ou) para produzir um valor booleano. Tal assertion lgica no a Go-declarao completa em si mesma. verdade, se qualquer um dos operandos verdade, ele s d falso se ambos os operandos so 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 expresso inteira (com falsa e verdadeiroa com && | |), em seguida, o lado direito no mais calculado. Por essa razo: se uma das expresses envolve um clculo longlasting, colocar essa expresso no lado direito. Como em todas as expresses, ( ) 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 so mais frequentemente utilizados (como valores ou combinado com os seus operadores) para testar as condies de se -, para-se mudar-afirmaes. A conveno de nomenclatura til para valores booleanos e funes importantes deixar o nome comear com ou, como IsSorted, isFound, isFinished, isVisible, ento declaraes if-cdigo l como uma sentena normal, por exemplo: unicode.IsDigit (ch).
CURSO GRATUITO
Lgico NO operador; falso se expresso booleana b verdadeiroo Curto-circuito operador lgico OR; verdadeiroo se qualquer expresso booleana um ou b Curto-circuito operador lgico AND; verdadeiroo se tanto Boolean expresses uma e b so verdadeiroo se a expresso x menor do que a expresso y verdadeiroo se a expresso x menor ou igual a Y expresso verdadeiroo se a expresso x igual a expresso y verdadeiroo se a expresso x no igual a expresso y verdadeiroo se a expresso x superior ou igual expresso y verdadeiroo se a expresso x maior do que a expresso y
Tipos numricos
Um tipo determina o conjunto de valores e operaes especficas para valores desse tipo. Tipos podem ser nomeado ou no. Tipos nomeados so especificadas por um (possivelmente qualificado) digite o nome, tipos annimos so especificados usando um tipo literal, que compe um novo tipo de tipos existentes. Type TypeName TypeLit = TypeName | TypeLit | "(" Type ")" . = identifier | QualifiedIdent . = ArrayType | StructType | PointerType | FunctionType | InterfaceType | SliceType | MapType | ChannelType .
Go oferece 11 tipos inteiros separados, cinco assinado e cinco no assinado , alm de um in -Type Teger para armazenar ponteiros. Go permite o uso de byte como um sinnimo para o no assinado uint8 tipo , e incentiva o uso de rune como um sinnimo para o tipo int32 quando trabalhar com caracteres individuais de cdigo Unicode ). No h hierarquia de tipo, para tornar a execuo e compilao mais rapida e o cdigos mais limpo. Go inteiros suportar todas as operaes aritmticas, alm disso, apoiar todas as operaes aritmticas e bit a bit. Todas essas operaes tm os comportamentos padro esperado . Um tipo numrico representa conjuntos de valores inteiros ou de ponto flutuante. Os tipos numricos independentes de arquitetura predeclarada so:
byte o sinnimo 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 (avanado) rune o sinnimo 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 nmeros de 32-bit de ponto flutuante IEEE-754 Float64 o conjunto de todos os nmeros de 64-bit de ponto flutuante IEEE-754 complex64 o conjunto de todos os nmeros complexos, com partes float32 reais e imaginrios complex128 o conjunto de todos os nmeros complexos, com partes Float64 reais e imaginrios int o tipo inteiro que oferece as velocidades de processamento mais rpido. O apoio da Go para inteiros de 64 bits faz com que seja realisticamente possvel a utilizao em escala
CURSO GRATUITO
inteiros para clculos precisos em alguns contextos. Go tem arquitetura tipos dependentes, como int,uint, UIntPtr. Eles tm o comprimento adequado para a mquina na qual o programa executado: Um int o tipo assinado padro: leva de 32 bits (4 bytes) em uma mquina de 32 bits e 64 bits (8 bytes) em uma mquina de 64 bits, o mesmo vale para o uint no assinado. Nmeros inteiros - como sua contraparte matemtica - so nmeros sem um componente decimal. (..., -3, 2, -1, 0, 1, ...) Ao contrrio do sistema decimal base 10 que usamos para representar nmeros, os computadores utilizam uma base-2 sistemas binrios. Um inteiro literal uma sequncia de dgitos que representam uma constante inteira. Um prefixo opcional define uma base no 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 alegricos este 0.0 A float32 confivel preciso de cerca de 7 casas decimais, um float64 para cerca de 15 casas decimais. Devido ao fato de que a preciso perfeita no possvel para flutuadores, comparando -os com == ou = deve ser feita com muito cuidado, e se necessrio um teste sobre a diferena menor do que um nmero muito pequeno (o limite de preciso) deve ser feita. Use float64 sempre que possvel, porque todas as funes do pacote de matemtica esperar que tipo. Os nmeros podem ser denotado em notao octal com um prefixo de 0 (como 077), hexadecimal com o prefixo 0x (como 0xFF) ou a notao cientfica com e, que representa a potncia de 10 (por exemplo: 1e3 = 1000 ou 6.022e23 = 6,022 x 1023). Voc pode fazer um nmero como este: a : = Uint64 (0) que , de fato, a converso de tipo a uint64 Porque Go fortemente tipado, a mistura de tipos no permitido, como no seguinte programa. Mas constantes so considerados no tipificado, a este respeito, por isso, com constantes de mistura permitida. package main func 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 : no pode usar a + um (tipo int) como tipo int32 em atribuio Da mesma forma um int16 no pode ser atribudo a um int32, no h correlao implcita, deve -se fazer a converso.
package main import fmt func main( ) { var n int16 = 34 var m int32 / / Erro do compilador: no pode usar n (tipo int16) como tipo int32 em atribuio / /m = n m = int32(n) fmt.Printf(32 bit int is: % d \ n ", m)
CURSO GRATUITO
fmt.Printf(16 bit int is: % d \ n ", n) } / / A sada : 32 bit int is: 34 16 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 representao hexadecimal), g% utilizado para tipos float (% f d um ponto flutuante, % e d uma notao cientfica), % 0ND mostra um inteiro com n dgitos, e levando 0 necessrio. % n.mg representa o nmero com m dgitos aps o sinal decimal, e n, antes disso, em vez de g tambm e f pode ser usado, por exemplo: o% 5.2e formatao do valor 3,4 d 3,40 E +00 Converses de valores numricos: Em uma converso como a32bitInt = int32 (a32Float) truncamento da parte decimal ocorre. Em geral a informao perdida durante a converso para um tipo menor, portanto, a fim de evitar a perda de preciso sempre converter para o tipo numrico maior. Ou voc pode escrever funes adequadas para realizar converses 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 / / Converso 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 { 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 no sentar no intervalo inteiro, o programa pra com uma mensagem de panic. Pergunta 4.1: Voc int e int64 do mesmo tipo? Para nmeros complexos, temos os seguintes tipos: complex64 (Com uma parte de 32 bits reais e imaginrios) complex128 (com uma parte de 64 bits reais e imaginrios) Um nmero complexo escrito na forma: re + imi, onde re a parte real, e im a parte imaginria e i a -1.Exemplo: var c1 complex64 = 5 + 10i fmt.Printf (The value is: %v, c1) / / Isso vai imprimir: 5 + 10i Se re e im so do tipo float32, uma varivel do tipo c complex64 pode ser feita com o complexo de funo: c = complex (re, im) As funes real (c) e imag (c) dar a parte real e imaginria, respectivamente. Em formato de strings % v o especificador de formato padro pode ser usado para nmeros complexos, caso contrrio usar% f para ambas as partes constituintes. Os nmeros complexos suportar todas as operaes aritmticas normais como outros nmeros. Voc
CURSO GRATUITO
s pode comparar com == e !=, Mas mais uma vez estar ciente de preciso. O cmath pacote contm funes comuns para operar com nmeros complexos. Quando restries de memria no esto muito apertadas, use tipo complex128 porque todas as funes cmath us -lo. Nmeros de ponto flutuante so nmeros que contm um componente decimal (nmeros reais). Sua representao real em um computador bastante complicado: 1. Nmeros de ponto flutuante so inexatos. Ocasionalmente no possvel representar um nmero. 2. Como inteiros nmeros de ponto flutuante tem um certo tamanho Tain (32 bits ou 64 bits). Utilizando um tamanho maior nmero de ponto flutuante aumenta preciso. 3. Em adio aos nmeros existem vrios outros valores que podem ser representados: "no um nmeros (NaN, Para coisas como 0/0) E positivo e infinito negativo. (+ e - ) Go tem dois tipos de ponto flutuante: float32 e float64 (Tambm muitas vezes referida como preciso simples e dupla preciso, respectivamente), bem como dois tipos adicionais para representar nmeros complexos (nmeros com partes imaginrias): complex64 e complex128. Um ponto flutuante literal uma representao decimal de uma constante de ponto flutuante. Ele tem uma parte inteira, um ponto decimal, uma parte fracionria, e uma parte expoente. O inteiro e parte fracionria compreendem dgitos decimais, a parte expoente um e ou E seguido de um expoente decimal opcionalmente assinado. Um dos parte inteira ou a parte fracionria 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 imaginrio uma representao decimal da parte imaginria de um complexo constante. Ele consiste de um literal de ponto flutuante inteiro ou decimal seguido pela letra minscula 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 cdigo Unicode. Um literal rune expresso como um ou mais caracteres entre aspas simples. Dentro das citaes, qualquer personagem pode aparecer exceto aspas simples e de nova linha. Um nico caractere citado representa o valor Unicode do prprio personagem, enquanto sequncias multicarter comea com uma barra invertida valores codificar em vrios formatos. A forma mais simples representa o carter nico dentro das aspas, uma vez Go texto de origem caracteres Unicode codificados em UTF8, vrios 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
CURSO GRATUITO
x e 4. Vrios escapes de barra invertida permitir valores arbitrrios para ser codificado como texto ASCII. H quatro formas de representar o valor inteiro como uma constante numrica: \ x seguido por exatamente dois dgitos hexadecimais; \ u, seguido por exatamente quatro dgitos hexadecimais; \ U seguido por exatamente oito dgitos hexadecimais, e uma barra invertida simples \ seguido por exatamente trs dgitos octais. Em cada caso, o valor do literal o valor representado pelos dgitos na base correspondente. Embora essas representaes tudo resultar em um nmero inteiro, eles tm diferentes intervalos vlidos. Escapes Octal deve representar um valor entre 0 e 255, inclusive. Escapes hexadecimais satisfazer essa condio pela construo. Os escapes \ u e \ U representam pontos de cdigo Unicode para que dentro deles alguns valores so 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 sequncias comeam com uma barra invertida so literais runes dentro ilegais. \a \b \f \n \r \t \v \\ \' \" U+0007 U+0008 U+000C U+000A U+000D U+0009 U+000b U+005c U+0027 U+0022 alerta ou sino retrocesso alimentao de formulrio alimentao de linha ou de nova linha retorno de carro guia horizontal tabulao vertical barra invertida aspas simples (escape vlido somente dentro de literais de runes) aspas duplas (escape vlido somente dentro strings literais)
Todas as outras sequncias comeam com uma barra invertida so literais runes dentro ilegais. rune_lit = "'" ( unicode_value | byte_value ) "'" . = unicode_char | little_u_value | big_u_value | escaped_char . = octal_byte_value | hex_byte_value. = `\` octal_digit octal_digit octal_digit . = `\` "x" hex_digit hex_digit . = `\` "u" hex_digit hex_digit hex_digit hex_digit . = `\` "U" hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit . = `\` (a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ).
unicode_value byte_value octal_byte_value hex_byte_value little_u_value big_u_value escaped_char 'a' '' '' '\t' '\000' '\007' '\377' '\x07' '\xff' '\u12e4' '\U00101234' 'aa' '\xa' '\0' '\uDFFF' '\U00110000
muitos caracteres muito poucos dgitos hexadecimais muito poucos dgitos octais metade substituto invlido ponto de cdigo Unicode
Os operadores Operadores combinar operandos em expresses. Expression = UnaryExpr | Expression binary_op UnaryExpr .
CURSO GRATUITO
UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "| |" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "=" | "<" | "<=" | ">" | "> =". add_op = "+" | "-" | "|" | "^". mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "& ^". unary_op = "+" | "-" | "!" | "^" | "*" | "E" | "<-". Comparaes so discutidas em outro lugar. Para outros operadores binrios, os tipos de operando deve ser idntico a menos que a operao envolve turnos ou sem tipo constantes. O operando da direita em uma expresso de mudana 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 expresso de mudana no constante uma constante sem tipo, o tipo da constante o que seria se a expresso turno foram substitudas 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 so 32bits em tamanho var o = 1 << s << == 2 s / / 1 e 2 tm tipo int; o == true se ints so 32bits em tamanho var p = 1 << s == 1 << 33 / / ilegal se ints so 32bits de tamanho: 1 tem o tipo int, mas um << 33 overflows int var u = 1,0 << s / / ilegal: 1.0 tem tipo float64, no pode mudar ! var u1 = 1,0 << s = 0 / / ilegal: 1.0 tem tipo float64, no pode mudar var u2 = 1 << s = 1.0 / / ilegal: 1 tem o tipo float64, no pode mudar var v float32 = 1 << s / / ilegal: 1 tem o tipo float32, no pode mudar var w int64 = 1,0 << 33 / / 1,0 << 33 uma expresso constante mudana
(. Em contraste com a regra geral, isto poderia ser chamado de uma forma de sobrecarga de operador, alm disso o operador + tambm existe para strings, mas fora isso Go no permite a sobrecarga de operador) / para inteiros a diviso inteira, por exemplo: 9 / 4 -> 2. O operador mdulo% s definido para inteiros: 9% 4 -> 1 Diviso por 0 faz com que o programa deixe de funcionar, um panic de tempo de execuo ocorre (se bvio, em seguida, o compilador pode detect -lo), ver Captulo 13 para saber como testar isso corretamente. Diviso por 0,0 com nmeros de ponto flutuante d um resultado infinito: + Inf Os operadores aritmticos aplica a valores numricos e de produzir um resultado do mesmo tipo que o primeiro operando. Os quatro operadores aritmticos padro ( + , - , * , / ) se aplicam para inteiro, ponto flutuante, e tipos complexos; + tambm se aplica s strings. Todos os outros operadores aritmticos aplicam-se apenas nmeros inteiros. + inteiros soma, carros alegricos, valores complexos, strings - diferena de nmeros inteiros, flutuantes valores complexos * inteiros de produtos, carros alegricos, valores complexos / inteiros quociente, carros alegricos, valores complexos % inteiros restantes & AND bit a bit inteiros | OR bit a bit inteiros ^ inteiros bit a bit XOR & ^ inteiros pouco claras (ou no) << Desvio esquerda inteiro << inteiro sem sinal >> Inteiro deslocamento para a direita >> inteiro sem sinal Strings podem ser concatenados utilizando o operador + operador ou o += operador de atribuio: s: = "oi" + string (c) s + = "e adeus" Alm de Strings cria uma nova string pela concatenao dos operandos. Por dois valores inteiros x e y , o quociente inteiro q = x / y e restante r = x % y satisfazer as seguintes relaes:
CURSO GRATUITO
x = q * y + r e | r | <| y | com x / y truncado para zero ( "diviso truncada" ). xyx / yx% y 5312 -5 3 -1 -2 5 -3 -1 2 -5 -3 1 -2 Como exceo 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 -9223372036854775808 Se o divisor uma constante, que no tem de ser igual a zero. Se o divisor zero em tempo de execuo, um panic de tempo de execuo ocorre. Se o dividendo no -negativo e divisor uma potncia constante de 2, a diviso pode ser substitudo por um deslocamento para a direita, e computando o restante pode ser substitudo por um bit a bit E operao: xx / 4 x 4 x% >> 2 x e 3 11 2 3 2 3 -11 -2 -3 -3 1 Os operadores de deslocamento move o operando esquerdo pelo conde turno especificado pelo operando direito. Eles implementar mudanas aritmticas se o operando esquerdo um inteiro assinado e mudanas lgicas se for um inteiro sem sinal. No h limite superior para a contagem de deslocamento. Mudanas se comportam como se o operando da esquerda deslocado n vezes em 1 para uma contagem de mudana 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 ^ so definidos como se segue: +X0+x -X negao 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 assinado Para os nmeros de ponto flutuante e complexos, +x igual a x, enquanto que -x a negao dos x. O resultado de uma diviso de ponto flutuante ou complexo por zero no especificado alm do padro IEEE 754, se um panic em tempo de execuo ocorre aplicao especfica. Existem atalhos para essas operaes: b = b + a pode ser encurtado para B + = a, e o mesmo vale para - =, * =, / = e% =. Como operadores unrios para nmeros inteiros e floats temos + + (incremento) e - (decremento), mas somente aps o nmero (postfix): i + + a abreviao de i + = 1 curto para i = i + 1 i - curto para i - = 1 curto para i = i - 1 Alm disso + + e - s podem ser utilizados como declaraes, e no expresses, de modo n = i + + invlido, e as expresses mais sutis, como f (i + +) ou A [i] = b [i + +], que so aceitos em C, C + + e Java, no pode ser usado em Go. Nenhum erro gerado quando um estouro ocorre durante uma operao: bits altos so simplesmente descartados. As constantes podem ser de grande ajuda aqui, e se voc precisa de nmeros inteiros ou nmeros racionais de tamanho ilimitado (que limitada apenas pela memria disponvel), voc pode usar o pacote grande da biblioteca padro, que fornece os tipos big.Int e big.Rat.
Os nmeros aleatrios
Alguns programas, como jogos ou aplicaes estatsticas precisam de nmeros aleatrios. O rand pacote implementa geradores de nmeros pseudoaleatrios. Para um exemplo simples veja a Listagem 4.10 -random.go, que imprime 10 inteiros no negativos aleatrios. package main import ( fmt
CURSO GRATUITO
rand time ) 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( )) } } Sada, 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 funes rand.Float32 e rand.Float64 retornar um nmero pseudoaleatrio desse tipo em [0.0, 1.0),), aqui, significa o limite superior no includas. O rand.Intn funo recebe um int n e retorna um nmero pseudoaleatrio no-negativo em [0, n). Voc pode usar a semente (valor) -funo para fornecer um valor inicial para a gerao pseudoaleatrio. Muitas vezes, o tempo de deslocamento atual em nano segundos usado para essa estreitolidade.
Operadores e precedncia
Alguns operadores tm prioridade (precedncia) do que os outros; operadores binrios do mesmo associado precedncia da esquerda para a direita. A tabela abaixo lista todos os operadores e sua precedncia, de cima para baixo (7 -> 1) maior para o menor: Precedncia 7 6 5 4 3 2 1 Operador (s) ^ ! * / % << >> & &^ + - | ^ == != < <= >= > <&& ||
, claro, permitido para esclarecer expresses usando ( ) para indicar a prioridade em operaes: expresses contidas em ( ) so sempre calculados em primeiro lugar. 4.5.4.Tipos Aliasing Quando se trabalha com os tipos, um tipo tambm pode ter um nome, de modo que este novo nome
CURSO GRATUITO
pode ser utilizado no cdigo (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 horrios em um programa), e pode, ento, ser usado para declarar int -variveis, como no seguinte programa: package main import fmt type TZ int func main( ) { var a, b TZ = 3, 4 c := a + b fmt.Printf(c has the value: %d, c) }
Na verdade este alias um novo tipo, que pode ter mtodos que o tipo original no tem; TZ pode ter um mtodo para a sada do fuso-info, de forma clara ou bonita.
Tipo de caractere
Estritamente falando, isso no um tipo de Go: caracteres so um caso especial de nmeros inteiros. O tipo byte um alias para uint8, e isso ok para o ASCII codificao 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, ento o seguinte so tambm as declaraes para o personagem A: var ch byte = 65 or var ch byte = \x41 (\ X sempre seguido por exatamente dois dgitos hexadecimais). Outra notao possvel a \ seguido por exatamente trs dgitos octais, por exemplo, '\ 377'. Mas existe tambm o suporte para Unicode (UTF-8): personagens tambm so chamados de pontos de cdigo Unicode ou runes, e um caractere Unicode representado por um int na memria. Na documentao so comumente representados como U + hhhh, onde h nos um dgito hexadecimal. Na verdade, o tipo de rune existe no Go e um apelido para o tipo int32. Para escrever um Unicode caracteres em cdigo prefcio 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 necessrios 4 bytes para o personagem \ U usado; \ u sempre seguido por exatamente quatro dgitos hexadecimais e \ U por 8. O cdigo a seguir var ch int = '\ u0041' var ch2 int = '\ u03B2' var ch3 int = '\ U00101234' fmt.Printf ("% d -% d -% d \ n", ch, CH2, CH3) / / inteiro fmt.Printf ("% c -% c -% c \ n", ch, CH2, CH3) / / personagem fmt.Printf ("% X - X% -% X \ n", ch, CH2, CH3) / / UTF-8 bytes fmt.Printf ("% U - U% -% U", ch, CH2, CH3) / / UTF-8 ponto de cdigo Imprime: 65 946-1053236 A - B- r 41 - 3B2 - 101234 L 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 nmero inteiro que representa o caractere;% U exibe a notao hhhh U +. O unicode pacote tem algumas funes teis para caracteres de teste, como o (ch um personagem):
CURSO GRATUITO
testes para a letra: testando por um dgito: teste para um personagem espaos em branco: unicode.IsLetter (ch) unicode.IsDigit (ch) unicode.IsSpace (ch)
Eles retornam um valor booleano. O pacote utf8 contm mais funes para trabalhar com runes.
Strings
Strings so uma sequncia de caracteres UTF-8 (o ASCII-cdigo 1 byte usado quando possvel, quando necessrio, um 2-4 byte de cdigo UTF-8). UTF-8 a codificao mais utilizado, a codificao padro para arquivos de texto, arquivos XML e JSON strings. Embora capaz de representar caracteres que precisam de 4 bytes, ASCII-personagens ainda so armazenados usando apenas 1 byte. Uma sequncia de Go , assim, uma sequncia de caracteres de largura varivel (cada 1 a 4 bytes, ver Ex. 4.6), ao contrrio do strings em outras linguagens como C + +, Java ou Python que so de largura fixa (Java usa sempre 2 bytes). As vantagens so que as strings Go e arquivos de texto ocupam menos espao de memria / disco, e uma vez que UTF-8 o padro, Go no precisa codificar e cadeias de decodificar como outros idiomas tem que fazer. Strings so tipos de valor e imutvel: uma vez criado no pode modificar o contedo da string; formulada de outra maneira: strings so arrays imutveis de bytes. 2 tipos de strings literais existem: Strings interpretadas: cercado por "" (aspas duplas), Sequncias de escape so 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 \ tambm pode ser usado para remover o significado especial da seguinte personagem, ento \ "simplesmente imprime a", e \ 'is', \ \ prints a \ Raw strings: Cercado por ''(aspas volta: AltGr + ), eles no so interpretados, pois eles pode abranger vrias linhas. Em `Esta uma string \ n` raw \ n no interpretado, mas tomado literalmente. Strings so delimitadas de comprimento e no terminar por um caractere especial, como em C / C + + O valor inicial (default) de uma string a string vazia "". Os operadores de comparao habituais (== != << => =>) Trabalhar em strings atravs da comparao byte por byte na memria. O comprimento de uma cadeia de str (o nmero de bytes) dado pela funo len ( ): len (str) O contedo de uma string (o bytes 'crua') acessvel atravs de mtodos de indexao padro, 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 endereo de um caractere em uma string, como & str [i], ilegal. Adicionando (concatenando)strings: +
CURSO GRATUITO
Duas sequncias S1 e S2 podem ser feitas em uma string s com: s: = s1 + s2 s2 anexado a S1 para formar uma nova string s. Strings multilinha pode ser construdo como se segue: str := "Incio da string" + "segunda parte da string " O + tem que estar na primeira linha, devido insero de; pelo compilador. A acrescentar taquigrafia + = tambm pode ser usado para strings: s: = "hel" + "lo" s + = "world!" fmt.Println (s) / / hello, world! Concatenao de strings em um loop usando + no 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 operaes de slice de indexao, assim, tambm se aplicam para strings.
O cstrings e ConvCad pacote Strings so uma estrutura de dados bsica, e cada lngua tem uma srie de funes pr -definidas para manipulao de strings. Em Go estes esto reunidos nas strings do pacote. Algumas funes muito teis so: Testes HasPrefix se a string s comea com o prefixo: strings.HasPrefix (s, prefix string) bool Testes 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")) } Sada: T / F? Ser que a string "Este um exemplo de uma cadeia" tm prefixo Th? Verdadeiroa. Isto ilustra tambm o uso da fuga caractere \ para a sada de um literal "com \", e uso de duas substituies em um formato de string.
Indicando em qual posio (ndice) uma substring ou caractere ocorre em uma string:
CURSO GRATUITO
strings.Index (s, string str) int LastIndex retorna o ndice da ltima instncia de str em s, ou -1 se str no est presente em s: strings.LastIndex (s, string str) int Se ch um no ASCII carter usa strings.IndexRune (s Um exemplo: package main import ( fmt strings ) func main( ) { var str string = Hi, Im 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 posio de "Marc" : 8 A posio da primeira ocorrncia de "Oi" : 0 A posio da ltima ocorrncia de "Oi" : 14 A posio de "Burger" : -1
Substituio de um texto:
Com strings.Replace (str, old, new, n), voc pode substituir as primeiras n ocorrncias de idade em str por novos. Uma cpia de str retornado, e se n = -1 todas as ocorrncias so substitudos. Contar o nmero de casos no-sobrepostas de substring str em s com: strings.Count (s, string str) int Um exemplo: package main import ( fmt strings ) func main( ) { var str string = Hello, how is it going, Hugo? var manyG = gggggggggg fmt.Printf(Number of Hs in %s is: , str) fmt.Printf(%d\n, strings.Count(str, H)) fmt.Printf(Number of double gs in %s is: , manyG) fmt.Printf(%d\n, strings.Count(manyG, gg)) Sada: Nmero de H's est em Hello, how is it going, Hugo? : 2 Nmero de g's da dupla em gggggggggg : 5
CURSO GRATUITO
Repeat retorna uma nova string que consiste de cpias contagem da string s: strings.Repeat(s, count int) string Um exemplo: package main import ( 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) }} Sada: A nova sequncia repetida : Hi there! Hi there! Hi there! Alterar o estado de uma string:
ToLower retorna uma cpia da string s com todas as letras Unicode mapeados para o seu caso mais baixo: strings.ToLower (s) string Todas as letras maisculas obtida com: Um exemplo: package main import ( fmt strings ) func main( ) { var orig string = Hey, how are you George? var lower string var upper string fmt.Printf ("A string original :% s \ n", orig) lower= strings.ToLower (orig) fmt.Printf ("A sequncia de letras minsculas :% s \ n", menor) upper = strings.ToUpper (orig) fmt.Printf ("A sequncia de letras maisculas :% s \ n", superior) } Sada: A string original : Hey, how are you George? (Ei, como voc est George?) A sequncia de letras minsculas : hey, how are you george? (ei, como voc est George?) A sequncia de letras maisculas : HEY, HOW ARE YOU GEORGE? (EI, COMO VOC EST GEORGE?)
CURSO GRATUITO
Aqui voc pode usar strings.TrimSpace (s) para remover todos os lderes e espaos em branco, se voc quiser especificar em um corte que personagens string para retirar, use strings.Trim (s, "corte"). Exemplo: strings.Trim (s, "\ r \ n") remove todas esquerda e direita \ r \ n da string s. A segunda string de parmetro pode conter quaisquer caracteres, que so 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 espao em branco: strings.Fields (s) divide a string s em torno de cada instncia de um ou mais caracteres de espao em branco consecutivos, retornando uma slice de substrings [ ] colar de s ou uma lista vazia se s contm apenas espao 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.
Isso resulta em uma string com todos os elementos da , separados por setembro: Strings.Join(sl [ ]string, sep string) Estas operaes simples so ilustrados na Listagem package main import ( 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) } / * Sada: 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
CURSO GRATUITO
*/
O pacote tem tambm uma funo strings.NewReader (str). Este procuces um apontador para um valor Reader, que fornece, entre outras, as seguintes funes de operar em str: Read( ) para ler um [ ]byte ReadByte ( ) e ReadRune ( ) : Para ler o prximo byte ou rune da string.
Esta funcionalidade oferecida pelo pacote ConvCad. Ele contm algumas variveis para calcular o tamanho em bits de um int da plataforma em que o programa executado: strconv.IntSize Para converter uma varivel de um determinado tipo T para uma string sempre ter xito. Para a converso de nmeros que tm as funes seguintes: strconv.Itoa (i int) string: Retorna a representao de string decimal de i strconv.FormatFloat (f float64, byte fmt, prec int, Bitsize int) string: converte o nmero de ponto flutuante de 64 bits f para uma cadeia, de acordo com o formato fmt (pode ser 'b', 'e', 'f' ou 'g'), preciso e prec Bitsize de 32 para float32 ou 64 para float64. Convertendo uma string para um outro tipo tp nem sempre ser possvel, nesse caso, um erro de tempo de execuo lanada: analisar "...": argumento invlido Para a converso de nmeros que tm as funes seguintes: strconv.Atoi (s string) (i int, err error) : Converter para um int strconv.ParseFloat (s string, Bitsize int) (f float64, err error) : Converter para a 64bit nmero de ponto flutuante Como pode ser visto a partir do tipo de retorno destas funes retornar dois valores: o valor convertido (se possvel) e da eventual erro. Assim, ao chamar essa funo a forma atribuio mltipla ser usado: val, err = strconv.Atoi (s) Neste programa ns desconsiderar a possvel converso de erros com o identificador em branco _: Package main import ( 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) } / * Sada:
CURSO GRATUITO
O tamanho de inteiros : 32 O inteiro : 222 A nova sequncia : 671 * /
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 prprio tempo-formatos como em: fmt.Printf(%02d.%02d.%4d\n, t.Day( ), t.Month( ), t.Year( )) / / e.g.: 21.07.2011 O tipo Durao representa o tempo decorrido entre dois instantes como uma contagem nanossegundo int64. O tipo de Mapas de localizao instantes para a zona em uso naquele tempo, UTC representa Horrio Coordenado Universal. H uma funo pr-definida funo (t Time) Format (string layout) string, que formata um tempo t em uma sequncia de acordo com uma sequncia de layout, com alguns formatos pr -definidos, como time.ANSIC ou time.RFC822 O layout geral define o formato de que mostra a representao de um padro de tempo, o qual ento 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 main import ( fmt time ) var wike time.Duration func 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 week_from_now: = t.Add (week ) fmt.Println (week_from_now) / / formatao de tempo: fmt.Println (t.Format (time.RFC822)) / / 21 11 dezembro 0852 UTC fmt.Println (t.Format (time.ANSIC)) / / Qua 21 dez 2011 08:56:34 fmt.Println (t.Format (02 Jan 2006 15:04)) / / 21 de dezembro de 2011 08:52 s: = t.Format ("20060102") fmt.Println (t, "=>", s) / / Qua 21 dez 0000 08:52:14 UTC 2011 => 20111221 } A sada mostrada aps o / / em cada linha. / / Deve estar em nano segundos / / Qua 28 dez 0000 08:52:14 UTC 2011
CURSO GRATUITO
Ponteiros
Ao contrrio de Java e NET, Go d o controle programador sobre o qual estrutura de dados um ponteiro e que no , no entanto voc no pode calcular com valores de ponteiros em programas. Ao dar o controle sobre o layout bsico programador memria, Go oferece -lhe a capacidade de controlar o tamanho total de um determinado conjunto de estruturas de dados, o nmero de alocaes e os padres de acesso memria, os quais so importantes para a construo de sistemas que executam bem: ponteiros so importantes para o desempenho e indispensvel se voc quer fazer programao de sistemas, perto do sistema operacional e de rede. Porque ponteiros so um tanto desconhecido para OO-programadores contemporneos, vamos explic-las aqui e nos prximos captulos de profundidade. Valores armazenar programas na memria, e cada bloco de memria (ou palavra) tem um endereo, que normalmente representado como um nmero hexadecimal, como 0x6b0820 ou 0xf84001d7f0 Go tem o operador de endereo e, que, quando colocado antes de uma varivel nos d o endereo de memria daquela varivel. O seguinte trecho de sadas de cdigo por exemplo: "Um nmero inteiro: 5, a sua localizao na memria: 0x6b0820" (este valor ser diferente cada vez que voc executar o programa!) var i1 = 5 fmt.Printf ("Um inteiro:% d, sua localizao na memria:% p \ n", i1, e i1) Este endereo 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 Ento, 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 endereo de memria do i1, que aponta para a localizao do i1, ele faz referncia a i1 varivel. Uma varivel ponteiro contm o endereo de memria de um outro valor: ele aponta para esse valor na memria e leva 4 bytes em mquinas de 32 bits, e 8 bytes em mquinas 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 recm-declarado que no tenha sido atribudo a uma varivel tem o valor nulo. Uma varivel ponteiro muitas vezes abreviado como ptr. !! Em uma expresso como var p *type de sempre deixar um espao entre o nome do ponteiro e * - tipo var p * sintaticamente correto, mas em expresses mais complexas, pode ser facilmente confundido com uma multiplicao! O mesmo smbolo * 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 referncia (ou contedo ou indireta) operador, outra maneira de dizer isso que o ponteiro est achatada. Assim, para qualquer varivel var o seguinte verdadeiroo: var == * (& var) Agora podemos entender o pointer.go programa completo e sua sada: package main import fmt func main( ) { var i1 = 5 fmt.Printf ("Um inteiro:% d, a sua localizao na memria:% p \ n", i1, e i1) var intp * int intp = & i1 fmt.Printf ("O valor na posio de memria% p % d \ n", INTP, * INTP) }
CURSO GRATUITO
Sada: Um inteiro: 5, a sua localizao na memria: 0x24f0820 O valor na posio de memria 5 0x24f0820
Programa d-nos um exemplo com strings. Isso mostra que a atribuio de um novo valor para *p altera o valor da prpria varivel (aqui uma string). package main import fmt func main( ) { s := good bye var p *string = &s *p = ciao fmt.Printf ("Aqui est o ponteiro p:% p \ n", p) / / Imprime endereo fmt.Printf ("Aqui est a string * p:% s \ n", * p) / / imprime cadeia fmt.Printf ("Aqui est a sequncia de s:% s \ n ", s) / / prints mesma sequncia } Sada: Aqui o ponteiro p: 0x2540820 Aqui a string * p: ciao Aqui a string s: ciao
Observao: voc no pode tomar o endereo de um literal ou uma constante, como o seguinte trecho de cdigo mostra: const i = 5 ptr: = & i / / erro: no possvel obter o endereo de i ptr2: = & 10 / / erro: no pode obter o endereo de 10 Ento Go, como a maioria dos outros de baixo nvel (sistema) linguagens como C, C + + e D, tem o conceito de ponteiros. Mas clculos com ponteiros (chamada de aritmtica de ponteiro, por exemplo ponteiro + 2, para percorrer os bytes de uma string ou as posies em uma array), que muitas vezes levam a acesso de memria errnea em C e acidentes fatais, assim, de programas, no so permitidos em Go, tornando segura a memria de linguagem. Ponteiros Go se assemelham mais as referncias de linguagens como Java, C # e VB.NET. Assim: c = *p + + o cdigo invlido Go! Uma vantagem dos ponteiros que voc pode passar uma referncia a uma varivel (por exemplo, como um parmetro para uma funo), em vez de passar uma cpia da varivel. Ponteiros so baratos para passar, apenas 4 ou 8 bytes. Quando o programa tem que trabalhar com variveis que ocupam muita memria, ou muitas variveis, ou ambos, trabalhando com ponteiros podem reduzir o uso de memria e aumentar a eficincia. Variveis destacou ainda persistem na memria, durante o tempo que existe pelo menos um ponteiro apontando para eles, ento a sua vida independente do escopo em que foram criados. Por outro lado (mas muito menos provvel), porque um ponteiro faz com que o que chamado de um engano (uma mudana no processamento para outro endereo), uso proibitivo deles poderia causar diminuio de desempenho. Ponteiros tambm pode apontar para outros ponteiros, e este aninhamento pode ser arbitrariamente profunda, de modo que voc pode ter vrios nveis de engano, mas na maioria dos casos, isso no contribuIr para a clareza do seu cdigo. Como veremos, em muitos casos, Go torna mais fcil para o programador e vai esconder indireta como, por exemplo, realizar uma desreferenciao automtica. A desreferenciava ponteiro nulo, como nas duas linhas a seguir, ilegal e faz uma falha de programa:
CURSO GRATUITO
package main func main( ) { var p *int = nil *p = 0 } / / No Windows: para somente com: <exit code="-1073741819" msg="process crashed"/> / / Erro de tempo de execuo: endereo de memria invlido ou nulo desreferenciava ponteiro
FLUXO DE CONTROLE Um algoritmo um texto esttico, onde temos vrios passos que so 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 dinmico. No fluxo de controle identificamos em cada passo da execuo qual o prximo comando a ser executado. A compreenso da lgica de programao de um algoritmo est diretamente ligada a compreenso de seu fluxo de controle. A partir de uma compreenso correta, podemos traar as diversas execues possveis de um algoritmo. Se testarmos todas essas possibilidades, e obtivermos resultados corretos, podemos ter certeza de estar entregando um produto estreitol confivel. Os iniciantes no mundo da programao encontram alguma dificuldade em diminuir a distncia conceitual que separa a representao esttica de um algoritmo do(s) processo(s) dinmico(s) de sua execuo. 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 comea a executar em main ( ) e sequencialmente executa os comandos nessa funo. Mas muitas vezes queremos executar certas declaraes apenas se uma condio for satisfeita: queremos tomar decises em nosso cdigo. Por esta Go fornece as seguintes estruturas condicionais ou ramificao: Se outra construo mudar caso construto selecionar construo, para a comutao entre os canais Repetindo uma ou mais declaraes (uma tarefa) pode ser feito com a estrutura iterativa ou looping: for (intervalo) construo Algumas outras palavras-chave como break e continue podem alterar o comportamento do loop. H tambm uma palavra -chave de retorno para deixar um conjunto de instrues e uma execuo de um rtulo no cdigo. Goto palavra -chave para saltar. Go totalmente omite os parnteses (e) em torno de condies em que, switch e for -loops, criando desordem visual menor do que em Java, C + + ou C #.
A construo if else
O teste if um (um booleano ou lgico) instruo condicional: se esta for avaliada como true o corpo de instrues entre { } aps o if executado, se for false estas declaraes so ignorados e a declarao aps o caso executado. if condition { / / Fazer alguma coisa } Em uma segunda variante de uma outra pessoa, com um corpo de afirmaes cercado por { }, anexado, que executado quando a condio falsa, temos ento dois ramos exclusivos (apenas um deles executado): if condition { / / Fazer alguma coisa } Else { / / Fazer outra coisa }
CURSO GRATUITO
Em uma terceira variante outro se a condio pode ser colocada aps a outra, por isso temos trs agncias exclusivas: if condition1 { / / Fazer alguma coisa } else if condition2 { / / Fazer outra coisa } Else { / / Catch-all ou default } O nmero de else e if, em princpio, no se limitando, mas por razes de legibilidade isso no deve ser exagerada. Ao utilizar este formulrio, coloque a condio que mais provvel verdade pela primeira vez. O { } so obrigatrios, tambm, quando h apenas uma instruo no corpo (algumas pessoas no gostam disso, mas por outro lado ela consistente e de acordo com princpios de engenharia de software tradicionais). O {aps 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 so obrigatrias para o compilador. Est um Go-cdigo invlido: if x { } else { }
/ / INVALIDO
Note que cada ramo recortado com 4 (ou 8) espaos ou um guia, e que o fechamento} esto alinhados verticalmente com o caso, o que reforado pela aplicao de gofmt. Enquanto ( ) em torno das condies no so necessrios, para as condies de complexos que podem ser utilizados para tornar mais claro o cdigo. A condio pode tambm ser composta, utilizando os operadores lgicos &&, | | e, com a utilizao de ( ) para impor a precedncia ou melhorar a legibilidade!.
package main import fmt func main( ) { bool1 := true if bool1 { fmt.Printf ("O valor vlido \ n") } Else { fmt.Printf ("O valor falsa \ n") } } / / sada: O valor true Note que no necessrio teste: se bool1 == true, porque bool1 j um valor booleano. quase sempre melhor para testar condies verdadeiroas ou positivos, mas possvel ensaiar para o reverso com! (No): if bool1! ou if (condio). No ltimo caso, o ( ) em torno a condio muitas vezes necessrio, por exemplo: if (var1 == var2). O idioma em Go-cdigo omitir a outra clusula em que o se fins em uma pausa, continuar, Go para ou retorno comunicado. Ao retornar diferentes valores de x e y ou no uma condio seja verdadeiroa uso o seguinte: IDIOMA if condition {
CURSO GRATUITO
return x } return y Observao: No use if / else com um retorno em ambos os ramos, isto no Ir compilar: "funcionar uma instruo de retorno" ( um erro de compilao 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 ( ) funo. Aqui est um trecho de cdigo que muda um aviso para conter o "fim do input 'correto:
var prompt = "Digite um dgito, 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 funo Abs para dar o valor absoluto de um inteiro: func Abs(x int) int { if x < 0 { return -x } return x } (4) Um isGreater funo para comparar dois nmeros inteiros: func isGreater(x, y int) bool { if x > y { return true } return false } Em uma quarta variante do se pode comear com uma declarao de inicializao (em que um valor
CURSO GRATUITO
atribudo a uma varivel). Este assume a forma (a, aps a inicializao obrigatrio): if initialization; condition { / / Fazer alguma coisa } 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 ateno que, na forma mais concisa, o val varivel inicializada com: = s conhecido dentro da instruo if (o escopo limitado a as declaraes em { }, mas se h uma outra clusula val tambm conhecido l) : se uma varivel val existia no cdigo antes do caso, o seu valor est escondido durante o bloco if. Uma soluo simples para isso no usar: = no caso de inicializao. package main import 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) } Sada: primeiro 5 ou maior cond no maior do que 10 O seguinte trecho de cdigo 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 { ... }
CURSO GRATUITO
Muitas vezes funes no Go so definidos de modo que eles retornam dois valores com a execuo bem-sucedida: o valor era verdade, e com a execuo bem sucedida: a 0 (ou o valor nulo) e falso. Em vez de verdadeiroo e falso, uma varivel de erro pode ser devolvido: no caso de execuo bem -sucedida, o erro zero, caso contrrio, ele contm a informao-erro. Em seguida, bvio para testar a execuo de uma instruo if, por causa da sua notao esta muitas vezes chamado a vrgula, por padro. No string_conversion.go programa a strconv.Atoi funo converte uma string para um inteiro. L ns desconsiderada um possvel erro de condio com: anInt, _ = strconv.Atoi(origStr) Se origStr no pode ser convertida para um inteiro, a funo retorna 0 para anInt, e a _ absorve o erro, o programa continua a ser executado. Isso no bom: um programa deve testar para cada erro que ocorre e se comportam de acordo, pelo menos, informar o utilizador (mundial) da condio de erro e voltar de, possivelmente, a funo ou mesmo travar o programa. Exemplo 1: package main import ( 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 cdigo } O idioma para testar se o err varivel de erro contm um erro real (se err! = Nil), nesse caso, uma mensagem apropriada impresso era execuo do programa deixa a funo de executar com retorno. Tambm poderia ter usado a forma de retorno que retorna uma varivel, como retorno err, ento a funo 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 execuo: Neste caso, foi main ( ) a execuo, para que o programa para. Se queremos que o programa pare em caso de um erro, podemos usar a funo 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)
CURSO GRATUITO
} (O nmero inteiro que dado para sair, aqui 1, pode ser testado em cima no script fora do programa) s vezes, esse idioma repetido vrias vezes em sucesso. Sem outra filial est escrito: se no houver um erro de condio, o cdigo simplesmente continua a execuo aps o se { }. Exemplo 2: ns 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 funo doSomething Exemplo 3: a produo eventual de um erro pode ocorrer na inicializao 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 inicializao tambm pode conter uma atribuio mltipla onde ok um retorno de valor bool, que testada, como a da seguinte forma: IDIOMA if value, ok := readData( ); ok { ... } Observao: Se voc acidentalmente esquecer um parmetro esquerda do sinal = de uma chamada de funo 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 compilao: multiple -value mySqrt ( ) em de valor nico contexto Ele deve ser: t, ok: = mySqrt (25,0) if ok {fmt.Println (t)} Observao 2: Quando voc est realmente certo de que as coisas que voc est lidando so inteiros e voc no quiser testar o valor de retorno em cada converso, voc pode envolver ATOI em uma funo com apenas
CURSO GRATUITO
retorna o inteiro, como: func atoi (s string) (n int) { n, _ = strconv.Atoi(s) return } Na verdade at mesmo as simples impresso de funes de fmt. Tambm retornam dois valores: count, err := fmt.Println(x) / / Nmero de bytes impressos, nulo ou 0, o erro
Ao imprimir para o console estes no so verificados, mas ao imprimir arquivos, conexes de rede, etc. o valor de erro deve ser sempre verificada.
A palavra-chave switch
Go totalmente omite os parnteses (e ) em torno de condies em que, switch e for-loops, criando menos desordem visual do que em Java , C + + ou C # Em comparao com o C, Java, switch na Go consideravelmente mais flexvel. Ele toma a forma geral onde uma varivel que pode ser de qualquer tipo possveis valores que precisam ser constantes ou inteiros , mas eles devem ser do mesmo tipo ou expresses avaliar a esse tipo. Ele toma a forma geral: switch var1 { case val1: ... ... case val2: ... default: ... } Onde var1 uma varivel que pode ser de qualquer tipo, e val1, val2, so possveis valores de var1, pois eles no precisam ser constantes ou inteiros, mas eles devem ser do mesmo tipo ou expresses 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 so apresentados em uma lista separada por vrgulas, como: caso val1, val2, val3: Cada caso ramo exclusiva, pois eles so julgados primeiro ao ltimo, coloque os valores mais provveis 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 implcito, sem dvida, um grande avano! Queda-through Ento automtico no o comportamento padro, 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 == 0 case 1: f ( ) / / f no chamado quando i == 0! } E: switch i { case 0: fallthrough case 1: f( ) / / f chamado quando i == 0!
CURSO GRATUITO
} Fallthrough tambm pode ser usado em uma hierarquia de casos em que em cada nvel algo tem de ser feito em adio ao cdigo j executado em casos de maior dimenso, e quando tambm uma ao padro tem de ser executado. Aps o caso : Vrias instrues podem seguir sem que eles sejam cercados por { }, mas chaves so permitidas. Quando h apenas uma instruo: ele pode ser colocado na mesma linha de processo. A ltima declarao de tal corpo tambm pode ser um retorno com ou sem expresso. Quando termina com uma instruo de retorno, tambm tem que ser uma instruo de retorno aps o} do switch. O (opcional) ramo default executado quando nenhum valor for encontrado para combinar com var1, assemelha-se a clusula else em declaraes if -else. Ele pode aparecer em qualquer lugar do switch (mesmo como primeiro ramo), mas o melhor escrito como o ltimo ramo. package main import fmt func main( ) { var num1 int = 100 switch num1 { case 98, 99: fmt.Println(Its equal to 98) case 100: fmt.Println(Its equal to 100) default: fmt.Println(Its not equal to 98 or 100) } } / / Output: " igual a 100"
Em uma segunda forma de uma switch nenhuma varivel necessria (isto , de fato, um switch true) e os casos podem testar diferentes condies. A primeira condio que verdade executado. Isso se parece muito com o encadeamento if-else, e oferece uma sintaxe mais legvel 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 comparao de igualdade, tal como ints, strings ou apontadores, pode ser utilizado nestas condies. Listagem 5.5-switch2.go: package main
CURSO GRATUITO
import "fmt" funo main ( ) { var num1 int = 7 switch { caso num1 <0: fmt.Println ("Nmero negativo") caso num1> 0 && num1 <10: fmt.Println ("Nmero entre 0 e 10") default: fmt.Println ("Nmero 10 ou maior") } } / / Saida: Nmero est entre 0 e 10 Como terceira forma e como o caso, um switch tambm pode conter uma instruo de inicializao: switch initialization { case val1: ... case val2: ... default: ... } Isso pode misturar muito bem com os testes caso de condies, como em: switch result := calculate( ); { case result < 0: / / ... case result > 0: / / ... default: //0 } Ou esse trecho, onde a e b so recuperados na inicializao paralela, e os casos so condies: switch a, b := x[i], y[j]; { case a < b: t = -1 case a == b: t = 0 case a > b: t = 1 } H tambm um switch de tipo que testa o tipo de uma varivel de interface. Pergunta 5.1: D a sada do seguinte trecho de cdigo: k := 6 switch 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) }
CURSO GRATUITO
A para construo
Somente a instruo for existe para repetir um conjunto de instrues um nmero de vezes, o que possvel, porque mais flexvel do que em outras lnguas. Uma passagem atravs do conjunto chamado de iterao. Observao: No h for-match para o Go enquanto instruo encontrada na maioria dos outros idiomas, provavelmente por causa do caso de uso para ele no era to importante.
A forma mais simples a iterao contra-controlado, como em for1.go: O formato geral : for init; condition; modif { }
package main import fmt func main( ) { for i := 0; i < 5; i++ { fmt.Printf(This is the %d iteration\n, i) } } Sada: Esta a iterao 0 Esta a iterao 1 Este o iterao 2 Esta a iterao 3 Este o iterao 4 O corpo { } do loop for repetido um nmero conhecido de vezes, isso contado por uma varivel (aqui i). As partidas de ala (por isso est realizada apenas uma vez) com uma inicializao para i (i: = 0), o que mais curto do que uma declarao de antemo. Isto seguido por uma verificao condicional em i (i <10), que realizado antes de cada iterao: quando verdadeiroa, a iterao feito, o loop for pra quando a condio se torna falsa. Em seguida, trata de uma modificao do i (i + +), a qual realizada depois de cada iterao, altura em que a condio verificada de novo para ver se o ciclo pode continuar. Essa modificao pode por exemplo ser tambm um decrscimo, ou + ou - usando um passo. Estes so trs declaraes separadas que formam o cabealho do loop, por isso eles so separados por, mas no h nenhum ( ) ao redor do cabealho: for (i = 0; i <10; i + +) { } o cdigo invlido! Mais uma vez a abertura {tem de estar na mesma linha que o para. A varivel contador deixa de existir aps a} do para, sempre use nomes curtos para ele como i, j, z ou ix. !! Nunca mude a contra-varivel no loop for em si, esta uma prtica ruim em todas as lnguas! package main import 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++ {
CURSO GRATUITO
fmt.Printf(Character on position %d is: %c \n, ix, str2[ix]) } } / * Sada: O comprimento de str: 27 Personagem em posio 0 : G Personagem em posio 1 : o Personagem em posio 2 : Personagem em posio 3 : i ... Personagem em posio 25 : e Personagem em posio 26 : O comprimento de cad2 : 9 Personagem em posio 0 : AE Personagem em posio 1 : Personagem em posio 2 : Personagem em posio 3 : AE Personagem em posio 4 : Personagem em posio 5 : Personagem em posio 6 : Personagem em posio 7 : a Personagem em posio 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 no -ASCII (que precisam de 2 a 4 bytes) o caractere indexado j no est correto!
A segunda forma no contm cabealho e usado para controlado por condio iterao (o loop while em outras lnguas), com o formato geral: para a condio { } Voc tambm pode argumentar que uma seo para sem inicializao e modif, para que o; so suprfluas. package main import fmt func main( ) { var i int = 5 for i >= 0 { i=i-1 fmt.Printf(The variable i is now: %d\n, i) } } Sada: A varivel i agora: 4 A varivel i agora: 3 A varivel i agora: 2 A varivel i agora: 1 A varivel i agora: 0 A varivel i agora: -1
CURSO GRATUITO
Loops infinitos
A condio pode estar ausente: como em for i: = 0; i + + ou por { } (ou para; { } mas o; removido por gofmt): estes so, de fato, loops infinitos. Este ltimo tambm pode ser escrito como: for verdadeiroa { }, mas o formato normal : para { } Se uma verificao de condio est faltando em um para-header, a condio de loop e permanece sempre verdadeiroo, por isso, o corpo do lao algo tem que acontecer para que o loop para ser encerrado aps um certo nmero de iteraes. Sempre tome cuidado para que a condio de sada Ir avaliar para true em um determinado momento, a fim de evitar um loop infinito! Este tipo de lao encerrado por uma instruo break (ver 5.5) ou uma instruo de retorno. Mas h uma diferena: quebrar apenas sadas do loop, enquanto as sadas de retorno da funo em que o loop codificado! Um uso tpico para um loop infinito uma funo 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 construo de gama
Esta a construo do iterador em Go e voc vai achar que til em muitos contextos. uma variao muito til e elegante, usado para fazer um loop sobre cada item em uma coleo. semelhante a um foreach em outras lnguas, mas ainda temos o ndice a cada iterao no loop. O formato geral : para ix, val: = gama coll { } Tenha cuidado: val aqui uma cpia do valor em que o ndice na coleo, assim que pode ser usado apenas para propsitos de leitura, o valor real da coleo no pode ser modificada atravs de val (tentar fazer isso!). Uma string um conjunto de Unicode caracteres (ou runes), de modo que ele pode ser aplicado para strings tambm. Se str uma string, voc pode fazer um loop sobre ele com: for pos, char := range str { ... } Cada caractere rune e seus ps ndices esto disponveis para processamento dentro do loop. Ele corompe caracteres Unicode individuais ao analisar o UTF-8 (codificaes erradas consumir um byte e produzem a rune substituio U + FFFD).
-Break / continue
Usando intervalo, o cdigo do poderia ento 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 } }
CURSO GRATUITO
Assim, em cada iterao uma condio (aqui i <0) tem de ser verificada para ver se o loop deve parar. Se a condio de sada torna-se verdadeiroa, o loop deixado pela instruo break. A instruo break sempre Corrompe da estrutura mais interna em que ela ocorre, que pode ser usado em qualquer tipo de loop for (contador, condio, etc.), mas tambm em um switch ou um select -statement. Execuo continua aps o trmino} dessa estrutura. No exemplo a seguir, com um loop aninhado (for4.go) break sai do loop mais interno: Listagem 5.11-for4.go: package main package main func 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 prxima iterao do loop aps a verificao do estado de conservao: package main func main( ) { for i := 0; i < 10; i++ { if i == 5 { continue } print(i) print( ) } } Sada: 0 1 2 3 4 6 7 8 9 5 ignorado A palavra-chave continuar apenas pode ser utilizado dentro de uma for-loop.
A linha de cdigo que comea a por, switch ou instruo select pode ser decorada com um rtulo do identificador forma: A primeira palavra que termina com dois pontos, e que precede o cdigo (gofmt coloca na linha anterior) um rtulo, como LABEL1: (O nome de um rtulo case-sensive, ele colocado em maisculas por conveno para aumentar a legibilidade.) package main import fmt func main( ) { LABEL1:
CURSO GRATUITO
for i := 0; i <= 5; i++ { for j := 0; j <= 5; j++ { if j == 4 { continue LABEL1 } fmt.Printf(i is: %d, and j is: %d\n, i, j) } } } Aqui continuar aponta para LABEL1, a execuo salta para o rtulo. Voc v que os casos j == 4 e j == 5 no aparecem na sada: o rtulo precede o loop externo, que comea i na sua prxima valor, fazendo com que o j no interior loop for para repor a 0 em sua inicializao . Da mesma forma pausa LABEL pode ser usado, no s a partir de um loop for, mas tambm para sair de um switch . Existe at uma palavra-chave Goto, que tem de ser seguido por um nome de etiqueta: package main func main( ) { i:=0 HERE: print(i) i++ if i==5 { return } goto HERE } Que imprime 01234. Mas um goto para trs quicky leva a ilegvel 'spaghetti' -cdigo e no deve ser usado, h sempre uma alternativa melhor. !! O uso de etiquetas e, certamente, empreendedores desencorajado: pode levar rapidamente a m concepo do programa, o cdigo pode ser escrito quase sempre mais legvel, sem us-los. ! Um exemplo em que o uso de Goto aceitvel em simple_tcp_server.go programa do 15.1: h GOTO usado para saltar de um loop infinito de leitura e fechar a conexo com um cliente quando um erro de leitura ocorre nessa conexo. Declarando um rtulo e no us-lo um erro do compilador (etiqueta ...definido e no utilizada) Se voc realmente tem que usar goto, use -o apenas com rtulos para a frente (um rtulo que aparece no cdigo de um nmero de linhas aps a Goto), e no declarar quaisquer novas variveis entre os empreendedores e rtulo, porque isso pode levar a erros e resultados inesperados (no compila!): func main( ) { a := 1 goto TARGET / / erro de compilao: / / Goto TARGET salta sobre declarao de b em goto2.go: 8 b := 9 TARGET: b += a fmt.Printf ("a % v *** b % v", a, b) } Sada: a 1 *** b 4.241.844 Funes
Funes so os blocos bsicos no cdigo Go: eles so muito versteis de modo que mesmo se pode dizer que Go tem um monte de caractersticas de uma linguagem funcional. Cada programa composto por
CURSO GRATUITO
um nmero de funes: o bloco de cdigo base. Como o cdigo compilado Go a ordem na qual as funes so escritas no programa, no importa, mas para facilitar a leitura, melhor comear com main ( ) e escrever as funes em uma ordem lgica (por exemplo, a ordem de chamada). O seu principal objetivo quebrar um grande problema que requer muitas linhas de cdigo em uma srie de pequenas tarefas (funes). Alm disso, a mesma tarefa pode ser chamado vrias vezes, de modo que uma funo promove a reutilizao de cdigo. (Na verdade, um bom programa homenageia o princpio DRY, No se repita, o que significa que o cdigo que executa uma determinada tarefa pode aparecer apenas uma vez no programa.) A funo termina quando ele executou a sua ltima declarao (antes}), ou quando ele executa uma instruo de retorno, que pode ser com ou sem argumento, estes argumentos so os valores que as funes retorna de seu clculo. Um retorno simples pode tambm ser utilizado para estreitolizar um infinito loop for, ou para parar um goroutine. Existem 3 tipos de funes em Go: funes normais com um identificador Annimo ou funes lambda Mtodos Qualquer um destes pode ter parmetros e valores de retorno. A definio de todos os parmetros de funo e valores de retorno, juntamente com seus tipos, chamado a assinatura da funo. E, como um lembrete, um pr-requisito sintaxe: Esta invlido Go-cdigo: func g ( ) { }
/ / INVALIDO
A funo chamada ou chamado em cdigo, de uma forma geral como: pack1.Function (arg1, arg2, ..., argn) Onde a funo uma funo no pacote pack1 e arg1, etc., so os argumentos: os valores que so passados para os parmetros da funo. Quando uma funo chamada cpias dos argumentos so feitas e estes so ento passadas para a funo chamada. A invocao acontece no cdigo de outra funo: a funo de chamada. Uma funo pode chamar outras funes, tanto quanto necessrio, e estes, por sua vez chamada outras funes, e isso pode continuar com teoricamente sem limite (ou a pilha sobre a qual estas chamadas de funo so colocados est esgotado). Aqui est o exemplo mais simples de uma funo chamando outra funo: package main func main( ) { println(In main before calling greeting) greeting( ) println(In main after calling greeting) } func greeting( ) { println(In greeting: Hi!!!!!) } Sada: In main before calling greeting
CURSO GRATUITO
In greeting: Hi!!!!! In main after calling greeting Uma chamada de funo pode ter outra chamada de funo como argumento, desde que esta funo tem o mesmo nmero e tipos de argumentos na ordem correta que a primeira funo precisa, por exemplo: Suponha necessidades f1 3 argumentos f1 (a,b, c int), e F2 retornos trs argumentos: f2(a, b int) (int, int, int), ento esta pode ser uma chamada para f1: f1(f2(a, b)) Sobrecarga de funo, que a codificao duas ou mais funes em um programa com o mesmo nome da funo, mas uma lista de parmetros diferente e / ou um tipo de retorno diferente (s), no permitido em Go. Ele d o erro do compilador: funcname declarado novamente neste bloco, a declarao anterior no lineno A principal razo que as funes de sobrecarga fora o tempo de execuo para fazer uma correspondncia de tipo adicional que reduz o desempenho, sem sobrecarga significa apenas um despacho funo simples necessrio. Ento, voc precisa dar seus nomes originais funes apropriadas, provavelmente nomeados de acordo com a sua assinatura. Para declarante uma funo realizada fora Go, como uma rotina de montagem, basta dar o nome e assinatura, e nenhum corpo: func FlushICache (comear, UIntPtr estreitol) / / implementado externamente As funes tambm podem ser utilizados sob a forma de uma declarao, como funo do tipo, como em: type binOp func(int, int) int . Neste caso tambm o corpo { } omitido. Funtions so valores de primeira classe: podem ser atribudo a uma varivel, como em: add := binOp O suplemento varivel obtm uma referncia (pontos) para a funo e sabe a assinatura da funo que se refere, de modo que no possvel atribuir -lhe uma funo com uma assinatura diferente. Valores da funo pode ser comparada: so iguais se eles se referem mesma funo ou se ambos so nulas. A funo no pode ser declarada dentro de outra funo (sem nidificao), mas isso pode ser imitada usando funes annimas. Go tem at agora nenhum conceito de genricos, o que significa, por exemplo, a definio de uma funo que pode ser aplicada a um certo nmero de tipos de variveis. 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 reflexo. A complexidade do cdigo aumenta o uso dessas tcnicas e de desempenho baixos, por isso, quando o desempenho muito importante, melhor e vai produzir cdigo mais legvel para criar a funo explicitamente para cada tipo usado. Parmetros e valores de retorno
A funo pode receber parmetros para usar em seu cdigo, e ele pode retornar zero ou mais valores (quando mais valores so devolvidos uma fala muitas vezes de uma tupla de valores). Esta tambm uma grande melhoria em comparao com C, C + +, Java e C #, e particularmente til quando o teste ou no uma funo de execuo resultou em um erro Voltando (a) valor (es) feito com a palavra -chave de retorno. Na verdade, cada funo que retorna pelo menos 1 valor deve terminar com retorno ou panic. Cdigo aps o retorno no mesmo bloco no mais executado. Se o retorno for usado, ento todos os cdigos-path na funo deve terminar com uma instruo de retorno.
A forma padro no Go passar uma varivel como um argumento para uma funo por valor: a cpia feita dessa varivel (e os dados nele). A funo trabalha com e possivelmente muda a cpia, o valor original no alterado: Function (arg1). Se voc quiser funo a ser capaz de mudar o valor da prpria arg1 ('no lugar'), voc tem que passar o endereo de memria daquela varivel com e, esta chamada (passar) por referncia: Function (e arg1); efetivamente um ponteiro ento passada para a funo. Se a varivel que passado um ponteiro, o
CURSO GRATUITO
ponteiro copiado, no os dados que ele aponta, mas atravs do ponteiro a funo 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 cpia do objeto. Tipos de referncia, como slices (CH 7), maps (8 ch), interfaces (ch 10) e canais (CH 13) so passagem por referncia por padro (mesmo que o ponteiro no diretamente visvel no cdigo). Algumas funes apenas executar uma tarefa, e no 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 funes retornam valores, que pode ser nomeado ou no. No programa simple_function.go a funo recebe 3 parmetros int a, b e c e retorna um int (as linhas comentadas mostram cdigo alternativo mais detalhado, onde uma varivel local usado): package main import 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 } Sada: Multiplique 2 * 5 * 6 = 60 Quando se torna necessrio voltar mais do que 4 ou 5 valores de uma funo, melhor passar uma slice (ver captulo 7) que os valores so do mesmo tipo (homogneo), ou para usar um ponteiro para um struct 130The Way to Go (Veja o captulo 10) se eles so de tipo diferente (heterogneo). Passando um ponteiro como o que barato e permite modificar os dados no local. variveis de retorno nomeadas No programa seguinte multiple_return.go a funo recebe um parmetro int e retorna 2 ints; os valores de retorno so preenchidas em funo de chamada em um trabalho paralelo. As duas funes getX2AndX3 e getX2AndX3_2 mostrar como variveis de retorno sem nome ou nomes so usados. Quando houver mais de uma varivel de retorno sem nome, que deve ser colocado dentro de ( ), como (int, int) Denominada variveis utilizadas como parmetros de resultado so automaticamente inicializados com o valor zero, e uma vez que recebem o seu valor, um (vazio) instruo de retorno simples suficiente, alm disso, mesmo quando h apenas uma varivel de retorno chamado, ele tem que ser colocado dentro ( ). package main import fmt var num int = 10 var numx2, numx3 int func 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 }
CURSO GRATUITO
func getX2AndX3_2(input int) (x2 int, x3 int) { x2 = 2 * input x3 = 3 * input / / Retorno x2, x3 return } Sada: num = 10, 2x num = 20, 3x num = 30 num = 10, 2x num = 20, 3x num = 30 Ateno: devolver ou retorno var ok, mas erro de sintaxe: = inesperados, ponto e vrgula esperando ou nova linha ou} retorno var = expresso d um erro do compilador: Mesmo com variveis de retorno nomeados voc ainda pode ignorar os nomes e valores de retorno explcitos. Quando qualquer uma das variveis de resultado tem sido sombra (no uma boa prtica!) O comando return deve conter os nomes das variveis de resultado. !!Use variveis de retorno nomeados: eles fazem o cdigo 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 funo no tem parmetros e 3 valores de retorno, onde apenas o primeiro e terceiro valor de retorno so capturados em i1 e f1. package main import 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 } Sada: A int: 5, o flutuador; 7,500000 Outro exemplo de uma funo com dois parmetros e valores de retorno de 2, que calcula o valor mnimo e mximo dos parmetros 2 apresentado em minmax.go. package main import 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
CURSO GRATUITO
} else { / / a = b ou a < b min = b max = a } return } / / Sada: Mnima de: 65, mxima de: 78
Passando um ponteiro para uma funo no s conserva a memria, porque nenhuma cpia do valor feita. Ele tem tambm como efeito colateral que a varivel ou o objeto pode ser alterado dentro de funo, de modo que o objeto no tiver alterado para ser devolvido para a funo. Veja este o seguinte programa pouco, onde resposta, um ponteiro para um inteiro, est a ser alterada na prpria funo. package main import ( fmt ) / / Esta funo 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 didtico, mas muito mais til para mudar um grande objeto dentro de uma funo. No entanto, esta tcnica obscurece um pouco o que est acontecendo, o programador deve ser muito consciente deste efeito colateral e, se necessrio deixar claro para os usurios da funo atravs de um comentrio.
Se o ltimo parmetro de uma funo seguido por ... tipo, isso indica que a funo pode lidar com um nmero varivel de parmetros desse tipo, possivelmente, tambm 0: a chamada funo de paridade varivel: func myFunc (a, b, arg ... int) { } A funo recebe em virr uma slice do tipo (ver captulo 7), o qual pode ser transmitido para o _, v: = gama construo. Dada a funo era chamada: func Greeting(prefix string, who ...string) Greeting(hello:, Joe, Anna, Eileen) Saudao ("Ol", "Joe", "Anna", "Eileen") Dentro de saudao, que ter o valor [ ] string {"Joe","Anna","Eileen"}
CURSO GRATUITO
Se os parmetros so armazenados em um arr array, a funo pode ser chamada com o parmetro arr ... package main 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 } Sada: O mnimo : 0 O mnimo na arr array : 1 Defer e rastreamento
A palavra-chave de adiamento nos permite defer a execuo de uma instruo ou uma funo at o estreitol do delimitador funo (chamada): ele executa alguma coisa (uma funo ou uma expresso) quando a funo de incluso retornos (aps cada retorno e at mesmo quando um erro ocorreu no meio de executar a funo, no s um retorno no estreitol da funo), mas antes do} (Por que depois? Porque a prpria declarao de retorno pode ser uma expresso que faz alguma coisa, em vez de apenas dar de volta uma ou mais variveis). Defer se assemelha ao bloco, estreitolmente, em OO-lnguas como Java e C #, na maioria dos casos, ele tambm serve para liberar recursos alocados. package main import 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!) }
CURSO GRATUITO
Em Function1 na parte inferior! Function2: diferido at o fim da funo de chamada! (Compare a sada quando defer removido) Se o adiamento tem argumentos so avaliados na linha da instruo defer, o que ilustrado no seguinte trecho, onde a defer imprimir 0: func a( ) { i := 0 defer fmt.Println(i) i++ return } Quando muitos de defer so emitidos no cdigo, eles so executados no estreitol da funo, 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 so realizados antes de retornar de uma funo, por exemplo: 1) fechando um fluxo de arquivo: / / Abre um arquivo defer file.Close( ) 2) destravar um recurso bloqueado (mutex): mu.Lock ( ) defer mu.Unlock( ) 3) imprimir um rodap em um relatrio: PrintHeader ( ) defer printFooter ( ) 4) fechar uma conexo de banco de dados: / / Abre uma conexo com o banco defer disconnectFromDB( ) Pode ser til para manter o lquido de limpeza de cdigo e ento geralmente mais curtos. A lista a seguir simula caso 4): package main import fmt func main( ) { doDBOperations( ) } func connectToDB ( ) { fmt.Println( ok, connected to db ) } func disconnectFromDB ( ) { fmt.Println( ok, disconnected from db ) }
CURSO GRATUITO
func doDBOperations( ) { connectToDB( ) fmt.Println(Defering the database disconnect.) defer disconnectFromDB( ) / / funo chamada aqui com defer fmt.Println(Doing some DB operations ...) fmt.Println(Oops! some crash or network error ...) fmt.Println(Returning from function here!) return / /terminate the program / / Funo adiada executado aqui um pouco antes, na verdade, o retorno, mesmo se h um retorno ou estreitolizao anormal antes } / * Sada: ok, connected to db Defering 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 execuo de um programa a impresso de uma mensagem ao entrar e sair de certas funes. Isto pode ser feito com as duas funes 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 main import 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( ) } Sadas: entering: b in b entering: a win a leaving: a leaving: b
CURSO GRATUITO
Isso pode ser feito de forma mais sucinta: package main 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 parmetro e retornar valores de dentro da funo: Esta uma outra possibilidade de utilizao de defer o que pode vir a calhar durante a depurao: package main import ( 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
funes embutidas
Estas so funes 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 tm de operar em nvel 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 comunicao
CURSO GRATUITO
len cap len d o comprimento de uma srie de tipos (strings, arrays, slices, maps, canais), cap a capacidade, o armazenamento mximo (aplicvel apenas para slices e mapas) new make Ambos new e make so usados para alocao de memria: new para tipos de valor e tipos definidos pelo usurio, como estruturas. make para built-in tipos de referncia (slices, maps, canais). Eles so usados como funes 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 endereo, para que ele retorna um ponteiro para o tipo T. make(T) retorna uma varivel inicializada do tipo T, por isso faz mais trabalho do que o novo ! new ( ) uma funo, no se esquea de seus parnteses! Ele pode ser usado com os tipos primitivos, bem como: v: = new (int) / / v tem o tipo int * copy append usado para copiar e concatenao de slices panic recover ambos so utilizados em um mecanismo para os erros de manipulao print println funes de impresso de baixo nvel, usar o pacote fmt em produo de programas. Complexo real imag usado para fazer e manipular nmeros complexos
funes recursivas
Funes recursivas se torna mais fcil para trabalhar com estruturas de dados recursivas (tais como rvores binrias), mas que pode ser ineficiente para, por exemplo, realizarmos clculos numricos. Vamos comear com um exemplo muito simples (e ineficiente), s para mostrar como recurso feito. Quando uma funo usa recurso 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 funes repetidas, embora o problema adicional de limitada espao de pilha que pode afetar funes profundamente recursivas em algumas lnguas muito menos comum em programas de Go por causa da maneira Go gerencia a memria. Em algumas situaes recurso a melhor maneira de expressar um algoritmo.Encerramento e recurso so poderosos tecnicasde programao, que constituem a base de um paradigma conhecido como programao funcional. A maioria das pessoas vai achar programao mais difcil de entender do que uma abordagem baseada em loops, if, variveis e funes simples. Para entender melhor como isso funo funciona, vamos ver um exemplo didtico em Portugus: fatorial (2) : x 0 == ? No. ( x 2) Encontre o fatorial de x - 1 x 0 == ? No. ( x 1) Encontre o fatorial de x - 1 x 0 == ? Sim, retornar 1. retorno 1 * 1 retorno 2 * 1 Uma funo que se chamam em seu corpo chamada recursiva. O exemplo notrio o clculo do nmero da sequncia de Fibonacci, em que cada nmero representa a soma dos dois nmeros anteriores. A sequncia comea 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 main import fmt func main( ) { result := 0 for i:=0; i <= 10; i++ { result = fibonacci(i) fmt.Printf(fibonacci(%d) is: %d\n, i, result) }
CURSO GRATUITO
} func fibonacci(n int) (res int) { if n <= 1 { res = 1 } else { res = fibonacci(n-1) + fibonacci(n-2) } return } Sada: Fibonacci (0) 1 Fibonacci (1) 1 Fibonacci (2) 2 Fibonacci (3) 3 Fibonacci (4) 5 Fibonacci (5) 8 Fibonacci (6) 13 Fibonacci (7) 21 Fibonacci (8) 34 Fibonacci (9) 55 Fibonacci (10) 89
Muitos problemas tm uma soluo recursiva elegante, como o famoso algoritmo Quicksort. Um problema importante quando se utiliza funes recursivas estouro de pilha: isso pode ocorrer quando so necessrios um grande nmero de chamadas recursivas e os programas ficar sem memria pilha alocada. Isso pode ser resolvido usando uma tcnica chamada avaliao preguiosa, implementado em Go com um canal e um goroutine. Exerccio anterior resolve o problema de Fibonacci desta maneira. Funes mutuamente recursivas tambm pode ser usado em Go: estas so as funes que requerem uma outra. Devido ao processo de compilao Go, estas funes podem ser declaradas em qualquer ordem. Aqui est um exemplo simples: mesmo chama de estranho, e at mesmo as chamadas estranhas.
package main import ( fmt ) func main( ) { fmt.Printf(%d is even: is %t\n, 16, even(16)) 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 }
/ / 16 mesmo: verdade
CURSO GRATUITO
As funes podem ser usadas como parmetros em uma outra funo, a funo passada pode, ento, ser chamado de dentro do corpo dessa funo, por isso que comumente chamado de callback. Para ilustrar aqui um exemplo simples: package main import ( 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 funo de um parmetro a funo strings.IndexFunc ( ): Ele tem a funo 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 espao em branco primeiro na linha. Claro que voc pode fazer a sua prpria funo f, por exemplo: func IsAscii(c int) bool { if c > 255 { return false } return true } Depois vamos discutir um exemplo de uma funo que tem uma outra funo como um parmetro, no contexto de escrever um programa de cliente-servidor: type binOp func(a, b int) int func run(op binOp, req *Request) { ... } Closures (literais de funo) s vezes ns no queremos dar uma funo de um nome, ento vamos fazer uma funo annima (tambm conhecido sob os nomes de uma funo lambda, uma funo literal, ou um fecho), por exemplo: func (x,y int) int {return x + y} Essa funo no pode ficar por conta prpria (o compilador d o erro: declarao de no declarao corpo da funo fora), mas pode ser atribudo a uma varivel, que uma referncia a essa funo: fplus := func(x, y int) int { return x + y } Em seguida, invocada como se fplus era o nome da funo: Ou ele pode ser chamado diretamente: fplus(3,4) func(x, y int) int { return x + y } (3, 4)
Aqui est uma chamada para uma funo lambda, que calcula a soma de inteiros flutua at 1 milho, gofmt reformata uma funo lambda, desta forma: func ( ) { sum = 0,0
CURSO GRATUITO
for i := 1; i <= 1E6; i + + { sum += i } }() O primeiro ( ) a lista de parmetros e segue imediatamente aps a palavra -chave funo porque no h nenhuma funo de nome. O { } compem o corpo da funo, e ltimo par de ( ) representam a chamada da funo. Aqui est um exemplo de atribu-la a uma varivel, g no seguinte trecho (function_literal.go), que , em seguida, do tipo de funo: package main import 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) } } Sada: 0 - g do tipo func (int) e tem valor 0x681a80 1 - g do tipo func (int) e tem valor 0x681b00 2 - g do tipo func (int) e tem valor 0x681ac0 3 - g do tipo func (int) e tem valor 0x681400 Vemos que o tipo de g func (int), o seu valor um endereo de memria. Portanto, neste atribuio temos, de fato, uma varivel com um valor de funo: funes lambda podem ser atribudas a variveis e tratados como valores. Aplicao de fechamento: a funo que retorna outra funo Em function_return.go programa vemos funes Add2 e Adder que retornar outra funo func lambda (b int) int: func Add2( ) (func(b int) int) func Adder(a int) (func(b int) int) Add2 no tem parmetros, mas Adder leva um int como parmetro. Ns podemos fazer casos especiais de Adder e dar-lhes um nome. package main import fmt funo main ( ) { / /make uma funo Add2, dar-lhe um nome p2, e chamo: p2: = Add2 ( ) fmt.Printf ("Call Add2 por 3 d:% v \ n", p2 (3)) / / make uma funo especial Adder, um valor 3 recebe: TwoAdder: = Adder (2) fmt.Printf (The result is: %v\n, TwoAdder(3)) } func Add32 ( ) (func (b int) int) {
CURSO GRATUITO
return func(b int) int { return b + 2 } } func Adder(a int) (func(b int) int) { return func(b int) int { return a + b } } / * Sada: Call Add2 for 3 gives: 5 The result is: 5 */ Aqui (quase) a mesma funo utilizada de um modo ligeiramente diferente: package main import 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 atribudo a varivel f (o qual , em seguida, do tipo de funo (int) int) A sada : 1 - 21-321 Nas chamadas para f, delta no adicionador ( ) recebe, respectivamente, os valores de 1, 20 e 300. Ns vemos que entre chamadas de f o valor de x retido, por um lado 0 + 1 = 1, ento torna -se 1 + 20 = 21, ento 21 adicionado a 300 para dar o resultado 321: as lojas de funo lambda e acumula os valores de suas variveis: ele ainda tem acesso s variveis (locais) definidas na funo atual. Essas variveis locais tambm podem ser parmetros, como Adder (a int). Isto demonstra claramente que funes literais em Go so encerramentos. As variveis que a funo lambda usa ou atualizaes tambm podem ser declaradas fora do lambda, como neste trecho: var g int go func (int i) { s := 0 for j: = 0, j <i, j + + + = {s} j g=s } (1000) / / Passa argumento 1.000 para a funo de literal. A funo de lambda pode ser aplicada a todos os elementos de um conjunto, actualizando estas variveis. Em seguida, essas variveis podem ser usadas para representar ou calcular valores ou mdias globais.
CURSO GRATUITO
Debugando Closures
Em cincia da computao e na programao uma clausura uma funo que referencia variveis livres no contexto lxico. Uma clausura ocorre normalmente quando uma funo declarada dentro do corpo de outra, e a funo interior referncia variveis locais da funo exterior. Em tempo de execuo, quando a funo exterior executada, ento uma clausura formada, que consiste do cdigo da funo interior e referncias para quaisquer variveis no mbito da funo exterior que a clausura necessita. As clausuras so utilizadas para:
Bibliotecas de software podem permitir que os usurios customizem o comportamento passando clausuras como argumentos s funes importantes. Por exemplo, uma funo que classifique valores pode aceitar um argumento de clausura que compare os valores a ser classificados de acordo com um critrio definido pelo prprio usurio. As funes mltiplas podem ser produzidas num mesmo ambiente, permitindo -as de se comunicar confidencialmente. Sistemas de objetos podem ser construdos com clausuras. Por exemplo, Scheme padro no suporta programao orientada a objetos, mas h sistemas de objetos construdos para essa linguagem de programao com recurso a clausuras.
s vezes ns no queremos dar uma funo de um nome , ento vamos fazer uma funo annima (tambm conhecido sob os nomes de uma funo lambda , uma funo literal , ou um fecho ). Go suporta funes annimas e encerramentos e suas declarando funes annimas so muito leves. O apoio da Go para funes annimas mais uma reminiscncia do apoio funo annima em JavaScript, mas no o tipo frgil de apoio funo annima que voc comea com lambdas do Python (uma declarao somente) ou situao de Ruby, onde existem vrias maneiras para criar fechamentos. Um Closure uma funo que "captura " todas as constantes e variveis que so apresentar , no mesmo mbito , onde ele criado , se ele se refere a eles. este meios que o fechamento capaz de acessar tais constantes e variveis , quando o fechamento chamada , mesmo se ele for chamado longe do local onde ele foi criado. No faz importa se quaisquer constantes ou variveis capturadas ter sado do alcance to longo como um fecho que se refere a eles sejam mantidos vivos durante o fecho de usar . No Go, cada funo annima (ou funo literal , como so chamados no Go especificao ) um encerramento . Um fechamento criado usando quase a mesma sintaxe de uma funo normal,mas com uma diferena fundamental : O fechamento no tem nome (de modo a palavra -chave funo imediatamente seguido por um parntese de abertura ) . Para fazer uso de um ns fechamento normalmente atribu -lo a uma varivel ou coloc-lo em uma estrutura de dados (como um mapa ou slice ) . A palavra-chave de defer muitas vezes usado com uma funo lambda. Ele pode , ento, tambm alterar valores de retorno , desde que voc est usando parmetros de resultado nomeados. Funes lambda tambm pode ser lanado como um goroutine com go.Funes lambda so tambm chamados de fechamentos (um termo da teoria das linguagens funcionais) : eles podem se referir a variveis definidas em uma funo circundanteOutra forma de formular este : um fecho no escopo da funo em que declarada. Esse estado ento dividido entre a funo circundante e do encerramento , e as variveis de sobreviver, enquanto eles so acessveis. Na prtica, quando queremos criar muitas funes semelhantes, ao invs de fazer com que cada um, individualmente, muitas vezes usamos uma funo que retorna uma funo. Aqui est uma funo que retorna fbrica funes que adicionam um sufixo a um nome de arquivo, but somente se o isn sufixo, AOT j est presente. Tipos de funo no Go tambm pode ter mtodos. H dois efeitos colaterais para o fato de que tipos de funo podem ter mtodos em Go: em primeiro lugar, uma vez que qualquer tipo que pode ter mtodos podem satisfazer uma interface, tipos de funo em Go tambm pode ser encaixotado em tipos de interface vlidos. Em segundo lugar, uma vez que os mtodos em GO pode ter ou ponteiro ou valor receptores, podemos usar mtodos em funo ponteiros para mudar a funo que est sendo apontado na chamada do mtodo contexto. Uma funo que pode retornar outra funo e uma funo que tem uma outra funo como um parmetro so chamadas de funes de ordem superior, o que uma caracterstica da categoria de linguagens chamadas linguagens funcionais. Vimos que funciona tambm so valores, por isso claro que Go possui algumas das principais caractersticas de uma linguagem funcional. Closures so usados com frequncia em Go, muitas vezes em combinao com goroutines e canais. Ao analisar e depurar programas complexos com milhares de funes em diferentes cdigos -arquivos chamando um ao outro, que muitas vezes pode ser til saber em determinados pontos no programa o
CURSO GRATUITO
arquivo que est sendo executado e nmero da linha na mesma. Isso pode ser feito usando as funes especiais do runtime pacotes ou log. No pacote de tempo de execuo do Caller function ( ) fornece essas informaes, de modo que um fechamento onde ( ) poderia ser definido o que exige isso, e, em seguida, ser invocado sempre que necessrio: where( ) := func ( ) { _, file, line, _ := runtime.Caller(1) log.Printf(%s:%d, file, line) } where( ) / / Algum cdigo where( ) / / Um pouco mais de cdigo where( ) O mesmo pode ser conseguido atravs da criao de uma flag no pacote de log: log.SetFlags (log.Llongfile) log.Print ("") ou se voc gosta da brevidade do "onde": var where = log.Print func func1( ) { where( ) algum cdigo where( ) algum cdigo where( ) }
s vezes, interessante saber quanto tempo um determinado clculo levou, por exemplo, para comparar e benchmarking clculos. Uma maneira simples registrar o tempo de incio antes do clculo, e tempo do fim aps o clculo usando a funo Now ( ) do pacote de tempo, era diferena 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 pedao de cdigo sempre tempo a verso anterior era verso otimizada para ver que no um (o suficiente) vantagem significativa; no seguinte vemos uma otimizao aplicada que certamente vale a pena.
Ao fazer clculos pesados uma coisa que pode ser feito para aumentar o desempenho no repetir qualquer clculo que j foi feito e que devem ser reutilizadas. Em vez cache o valor calculado na memria, que chamado memoization. Um grande exemplo disso o programa de Fibonacci: Para calcular o nmero de Fibonacci n -th, voc precisa das duas precedentes, que normalmente j foram calculados. Se voc no estocar os resultados anteriores, a cada mais elevados de Fibonacci nmero
CURSO GRATUITO
resulta em uma avalanche cada vez maior de novos clculos, o que precisamente o que a verso da fibonnaci.go faz. Estoque simples do nmero de Fibonacci n -th em uma array no ndice n, e antes de calcular um Fibonnaci-nmero, procure primeiro na array, se ainda no foi calculado. Este princpio aplicado na fibonacci_memoization.go. O ganho de desempenho surpreendente, tempo ambos os programas para o clculo at o nmero Fibonnaci 40: Normalmente (fibonacci.go): o clculo leva essa quantidade de tempo: 4,730270 s com memoization: o clculo levou essa quantidade de tempo: 0.001000 s Neste algoritmo memoization bvio, mas que muitas vezes pode ser aplicado em outros clculos, bem como, talvez, atravs de mapas ao invs de arrays ou slices. Fibonacci_memoization.go: package main import ( fmt time ) const LIM = 41 var fibs [LIM]uint64 func 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 } Memoizao til para funes relativamente caros (no necessariamente recursiva como no exemplo) que so chamados lotes de vezes com os mesmos argumentos. Ele tambm pode ser aplicado apenas s funes puras, estas so funes que produzem sempre o mesmo resultado com os mesmos argumentos, e no tem efeitos secundrios.
Arrays e slices
Neste captulo vamos comear com a avaliar estruturas de dados que contm uma srie de itens, os chamados colees, como arrays (slices) e mapas. Aqui, a influncia Python bvio. O tipo de array, indicado pelo [ ], a notao bem conhecida em quase todas as linguagens de
CURSO GRATUITO
programao como o carro-chefe bsica em aplicaes. Uma array Go praticamente o mesmo, mas tem algumas peculiaridades. No to dinmico como em C, mas para isso Go tem o tipo de slice. Esta uma abstrao construda em cima do tipo array de Go, e assim entender slices devemos primeiro entender arrays. Arrays tm o seu lugar, mas eles so um pouco inflexvel, para que voc no v -los muitas vezes em cdigo Go. Slices, porm, esto em toda parte. Apoiam -se Arrays para fornecer grande poder e convenincia.
Declarao e inicializao Uma um numerado e sequncia de comprimento fixo de itens de dados (elementos) do mesmo tipo simples (que uma estrutura de dados homogneos), 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 expresso constante, que deve ser avaliada como um valor inteiro no negativo. Faz parte do tipo de array, assim como arrays declarados [5] int e [10] int diferem no tipo. A inicializao de uma Array com valores conhecidos em tempo de compilao feito com literais de array. O nmero de elementos chamada o comprimento e nunca negativo. ArrayType = "[" ArrayLength "]" ElementType . ArrayLength = Expression . ElementType = Type . Observao: 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 declarao de tipo. Os itens podem ser acessados (e alterados) atravs de seu ndice (a posio), o ndice comea a partir de 0, de modo que o primeiro elemento tem ndice 0, o segundo ndice 1, etc. (Arrays so baseadas em zero, como de costume no famlia de lnguas C). O nmero de itens, tambm 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 compilao, a fim de alocar a memria), o comprimento mximo de array de 2 Gb . O formato da declarao : var identifier [len]type Por exemplo: var arr1 [5]int Cada compartimento contm um inteiro, quando declarar uma array, cada item automaticamente inicializado com o valor de zero padro do tipo, aqui todos os itens padro 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 so mutveis. Somente ndices vlidos 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 contrrio, o cdigo compila muito bem e executar o programa vai dar o panic: Erro de execuo: ndice fora do intervalo. Por causa do ndice, uma maneira natural de loop sobre uma array usar o para -construo: para inicializar os itens da Array para imprimir os valores, ou, em geral: para procisso cada item em sucesso. Um exemplo bsico: package main import fmt func main( ) {
CURSO GRATUITO
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]) } } Sada: Array no ndice 0 0 Array no ndice 1 2 Array no ndice 2 4 Array no ndice 3 de 6 Array no ndice 4 de 8 Muito importante aqui a condio 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 construo de-gama tambm til: IDIOMA: for i:= range arr1 { ... } Aqui eu tambm o ndice na Array. Tanto para -construes tambm trabalhar para slices, claro. Uma array em Go um tipo de valor (e no 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 diferena com: var arr2 [5] int? arr1 do tipo *[5] int, arr2 do tipo [5] int. A consequncia que, quando a atribuio de uma array para outra, uma cpia distinta na memria da array feita. Por exemplo, quando: arr2 := arr1 arr2[2] = 100 Em seguida, as arrays tm valores diferentes, mudando arr2 aps a atribuio no muda arr1. Assim, quando uma array passada como um argumento para uma funo como em func1 (arr1), uma cpia da array feita, e func1 no pode mudar o arr1 array original. Se voc quer que isso seja possvel, ou voc quer uma soluo mais eficiente, ento arr1 devem ser passados por referncia com o & operador, como no func1 (& arr1), como no exemplo a seguir: package main import fmt func f(a [3]int) { fmt.Println(a) } func fp(a *[3]int) { fmt.Println(a) } func main( ) { var ar [3]int f(ar) / / Passa uma cpia do ar
CURSO GRATUITO
fp(&ar) } Sada: & [0 0 0] [0 0 0] / / passa um ponteiro para ar
Outra forma equivalente fazer com que uma slice da array e passar isso para a funo.
literais de array
Quando os valores (ou alguns deles) dos itens so conhecidos de antemo, existe uma inicializao mais simples usando o {,,} notao chamado literais de array (ou construtores), em vez de inicializar todos os itens do [ ] = caminho. (Todos os tipos compostos tm uma sintaxe semelhante para a criao de valores literais). package main import 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 mo esquerda [10] int {1, 2, 3}: este um array de 10 elementos com o 1, trs diferente de 0. Segunda variante: var arrLazy = [...] int {5, 6, 7, 8, 22} indica o compilador tem de contar o nmero de itens a obter o comprimento da Array. Mas [...] int no um tipo, ento isso ilegal: var arrLazy [...] int = [...] int {5, 6, 7, 8, 22} O tambm pode ser omitido (tecnicamente falando torna -se ento 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 esto definidos para strings vazias, como mostrado na sada: Person at 0 is Person at 1 is Person at 2 is Person at 3 is Chris Person at 4 is Ron Aqui tambm o comprimento pode ser escrito como ou mesmo ser omitida. Voc pode obter o endereo de uma array literal para obter um ponteiro para uma instncia recm criada, consulte Listagem package main import fmt func fp(a *[3]int) { fmt.Println(a) } func main( ) { for i := 0; i < 3; i++ {
CURSO GRATUITO
fp(&[3]int{i, i * i, i * i * i}) } } & [0 0 0] & [1 1 1] & [2 4 8] Pontos geomtricos (ou vetores matemticos) so um exemplo clssico do uso de arrays. Para esclarecer o cdigo muitas vezes um alias utilizado: type Vector3D [3] float32 var vec Vector3D Sada:
Arrays multidimensionais
As arrays so sempre de 1-dimensional, mas podem ser compostos para formar Arrays multidimensionais, como: [3] [5] int [2] [2] [2] float64 As Arrays interiores tm sempre o mesmo comprimento. Arrays multidimensionais da Go so retangulares (as nicas excees podem ser arrays de slices (slices). package main const ( WIDTH =1920 HEIGHT = 1080 ) type pixel int var screen [WIDTH][HEIGHT]pixel func main( ) { for y := 0; y < HEIGHT; y++ { for x := 0; x < WIDTH; x++ { screen[x][y] = 0 } } }
Passando arrays grandes para uma funo rapidamente consome muita memria. Existem 2 solues para evitar isso: 1 - Passe um ponteiro para a array 2 - Use uma slice da array O exemplo a seguir Listagem package main import fmt func main( ) { array := [3]float64{7.0, 8.5, 9.1} x := Sum(&array) / / Note a explcita operador de endereo / / Passar um ponteiro para a array fmt.Printf(The sum of the array is: %f, x) }
CURSO GRATUITO
func Sum(a *[3]float64) (sum float64) { for _, v := range a { / / Dereferencing * a voltar para a Array no necessrio! sum += v / / sada: A soma da Array : 24.600000
Slices (Slices)
Uma slice uma referncia a um segmento contguo (seo) de uma array (que chamaremos a array subjacente, e que normalmente annimo), ento uma slice um tipo de referncia (portanto, mais parecido com o tipo de array em C / C + + , ou o tipo de lista em Python). Esta seco pode ser toda a array, ou de um subconjunto dos itens indicados por um incio e um ndice estreitol (o item no ndice estreitol no est includo na slice). Slices fornecer uma janela dinmica para a array subjacente. As slices so intercambiveis e tm um comprimento determinado pelo len ( ) -funo. A slice ndice de um determinado artir pode ser menor do que o ndice de um mesmo elemento da array subjacente. Ao contrrio de uma array, o comprimento de uma slice pode alterar durante a execuo do cdigo, minimamente 0 e no mximo o comprimento da array subjacente: uma slice array de comprimento varivel. A tampa funo capacidade embutida ( ) de uma slice uma medida de quanto tempo uma slice pode tornar-se: o comprimento da slice + o comprimento da array para alm da slice. Se s um tampo 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) Vrias slices podem compartilhar dados se representam peas do mesmo array; vrias arrays nunca podem compartilhar dados. Portanto, uma slice partes de armazenamento com sua array subjacente e com outras slices da mesma array, pelo contrrio arrays distintas sempre representam armazenamento distinta. Arrays so em blocos de construo de fatos para slices. Vantagem: Porque slices so referncias, eles no usam a memria adicional e por isso so mais eficientes de usar do que as arrays, por isso eles so usados muito mais do que as arrays em Go-cdigo. O formato da declarao : var identifier [ ]type no h necessidade de comprimento. Uma slice que ainda no foi inicializado est definido para zero por padro, e tem comprimento 0. Formato de inicializao de uma slice: var slice1 [ ]type = arr1[start:end] Isto representa o sub array de arr1 composto dos itens do incio 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 algum escreve: var slice1 [ ] type = arr1 [:] ento 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 contm todos os itens da array da 2 at posterGomente. arr1 [00:03], contendo uma arr1[0:3] array-itens do 1 at (no 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 idnticos, mas ainda se refere a mesma array subjacente. Uma slice s pode ser expandido para seu tamanho mximo com: s = S [: cap (s)],qualquer maior d um erro em tempo de execuo Para cada slice (tambm para strings) o seguinte sempre verdadeiroo: s == s [: i] + s [i:] / / i um int: 0 <= i <= len (s) len (s) <= cap (s) Slices tambm podem ser inicializados como arrays: var x = [ ] int {2, 3, 5, 7, 11}
CURSO GRATUITO
O que isso faz criar uma array de comprimento 5 e, em seguida, criar uma slice para se referir a ele. Uma slice de memria de fato uma estrutura com trs domnios: 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] contm os elementos 3, 5, 7 e 11.
package main import fmt func main( ) { var arr1 [6]int var slice1 [ ]int = arr1[2:5] / / item no ndice 5 no includo! / / Carregar a array com nmeros 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 alm da capacidade: / / = Slice1 slice1 [00:07] / / panic: erro de tempo de execuo: slice limites fora da faixa }
Sada: Slice de 0 a 2 Slice de 1 a 3 Slice de 2 a 4 O comprimento de 6 arr1 O comprimento de 3 slice1 A capacidade de slice1 4 Slice de 0 a 2 Slice de 1 a 3 Slice de 2 a 4 Slice de 3 a 5 O comprimento de 4 slice1 A 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 no movido. Slices s podem avanar: s2 s2 = [ -1:] resulta em um erro de compilao. Slices no 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 referncia, por isso um ponteiro!!
CURSO GRATUITO
Passando uma slice para uma funo
Se voc tem uma funo que deve operar em uma array, provavelmente voc sempre quer declarar o parmetro formal para ser um slice. Quando voc chamar a funo, a slice de array para criar (de forma eficiente) uma referncia slice e passar essa. Por exemplo, aqui uma funo 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[:]) }
Muitas vezes, a array subjacente ainda no est definido, podemos ento 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 tambm o comprimento inicial da slice. Assim, para o s2 slice feito com: s2 := make([ ]int, 10) O seguinte verdadeiroo: tampa (s2) == len (s2) == 10 make leva 2 parmetros: o tipo a ser criados, bem como o nmero de itens na slice. Se voc quiser slice1 para no ocupar todo o conjunto (com tampa de comprimento), desde o incio, mas apenas um nmero len de itens, use o formulrio: slice1 := make([ ]type, len, cap) make tem a assinatura: make([ ]T, len, cap) [ ] T com tampa de parmetro opcional. Ento, as seguintes afirmaes resultam na mesma slice: make([ ]int, 50, 100) new([100]int)[0:50] Exemplo: package main import 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)) } Sada:
CURSO GRATUITO
Slice at 0 is 0 Slice at 1 is 5 Slice at 2 is 10 Slice at 3 is 15 Slice at 4 is 20 Slice at 5 is 25 Slice at 6 is 30 Slice at 7 is 35 Slice at 8 is 40 Slice at 9 is 45 O comprimento de 10 slice1 A capacidade de 10 de slice1 Diferena entre new( ) e make( ) Esta muitas vezes confusa primeira vista: ambos alocar memria 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 endereo, um valor do tipo * T: ele retorna um ponteiro para um valor recm -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 referncia: slices, mapas e canais. Em outras palavras, new aloca; make inicializa. Exemplo: var p *[ ]int = new([ ]int) ou p := new([ ]int) / / *p == nil; com len e cap 0
p: = make ([ ] int, 0) nossa slice inicializada, mas aqui aponta para uma array vazia. Ambas as declaraes no so muito teis: var v [ ] int = make ([ ] int, 10, 50) ou v: = 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 so sempre de 1 -dimensional, mas pode ser composta para construir objetos de dimenses superiores. Com slices de slice (ou arrays de slices), os comprimentos podem variar dinamicamente, ento slices multidimensionais do Go pode ser Irregular. Alm disso, as slices internas devem ser alocados individualmente (com o make).
O pacote de bytes
Slices de bytes so to comuns. Go tem um pacote de bytes com funes de manipulao para que tipo de tipo. muito semelhante ao pacote de strings. Alm disso, contm um tipo de buffer muito til: import bytes type Buffer struct { ...
CURSO GRATUITO
} um buffer de tamanho varivel de bytes com mtodos Read e Write, porque ler e escreve um nmero desconhecido de bytes o melhor feito em buffer. Um buffer pode ser criado como um valor como em: tampo var bytes.Buffer ou como um ponteiro com o novo como em: var r *bytes.Buffer = new(bytes.Buffer) ou criado com a funo: func NewBuffer(buf [ ]byte) *Buffer Cria e inicializa um novo buffer usando buf como seu contedo inicial, melhor usar NewBuffer s para ler o buf. A concatenao (unio) de sequncias de caracteres usando um buffer: Isso funciona anlogo a classe StringBuilder do Java. Faa um buffer, append cada string est nele com o mtodo buffer.WriteString (s), e converter no estreitol de volta para uma string com buffer.String ( ), como no seguinte trecho de cdigo: var buffer bytes.Buffer for { if s, ok := getNextString( ); ok {/ / mtodo getNextString ( ) no mostrado aqui buffer.WriteString(s) } else { break } } fmt.Print (buffer.String ( ), "\ n") Este mtodo muito mais do que memria e + = eficiente em termos de CPU, especialmente se o nmero de strings para concatenar grande.
Esta construo 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 so variveis locais conhecidos apenas no corpo do para-assertion, assim valor uma cpia do item slice nesse ndice e no pode ser utilizado para modificar o! package main import 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}
CURSO GRATUITO
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) } _ Pode ser usada para descartar o ndice. Se voc s precisa do ndice, voc pode omitir a segunda varivel, como em: for ix := range seasons { fmt.Printf(%d , ix) } / / Sada: 0 1 2 3 Use esta verso 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 nmero 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 mudana 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 1 Uma slice pode ser redimensionada at que ocupa todo o conjunto subjacente.
package main import 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]) } }
CURSO GRATUITO
Sada: The length of slice is 1 The length of slice is 2 The length of slice is 3 The length of slice is 4 The length of slice is 5 The length of slice is 6 The length of slice is 7 The length of slice is 8 The length of slice is 9 The length of slice is 10 Slice at 0 is 0 Slice at 1 is 1 Slice at 2 is 2 Slice at 3 is 3 Slice at 4 is 4 Slice at 5 is 5 Slice at 6 is 6 Slice at 7 is 7 Slice at 8 is 8 Slice 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] / / referncia a subarray {5,6} - len (a) 2 e cap(a) de 5 reslicing 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 contedo da slice original, para ele. O cdigo a seguir ilustra as funes copiar para copiar slice, e acrescentar para acrescentar novos valores a uma slice. package main import 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) / / Sada: [1 2 3 4 5 6] } funo append (s [ ] T, T x ...) [ ] T
O acrscimo funo acrescenta zero ou mais valores para uma slice s e retorna a slice resultante, com o mesmo tipo como s; os valores tm, naturalmente, de ser de tipo idntico ao do tipo de elemento de T s. Se a capacidade de s no 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 memria. Se voc quiser append uma slice y a uma slice x, use o seguinte formulrio para expandir o segundo
CURSO GRATUITO
argumento para uma lista de argumentos: x = append (x, y ...) Observao: append (append) bom para a maioria dos propsitos, no entanto, se voc quer controle total sobre o processo, voc pode usar um AppendByte funo como esta: func AppendByte(slice [ ]byte, data ...byte) [ ]byte { m := len(slice) n := m + len(data) if n > cap(slice) {/ / se necessrio, realocar / / Alocar o dobro do que necessrio, 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 cpias de cpia funo cortar elementos do tipo T a partir de uma origem para um src dst destino, substituindo os elementos correspondentes em dst, e retorna o nmero de elementos copiados. A origem e o destino podem se sobrepor. O nmero de argumentos copiados o mnimo de len (src) e len (dst). Quando src uma sequncia do tipo de elemento byte. Se voc quiser continuar a trabalhar com o src varivel, coloque: src = dst aps a cpia.
Vemos que Unicode caracteres levar 2 bytes; alguns personagens pode at ter 3 ou 4 bytes. Se errnea UTF-8 encontrado, o personagem est definido para U + FFFD e os avanos do ndice por um byte. Da mesma forma, a converso c: = [ ] int (s) permitido, ento cada int contm um cdigo de ponto de Unicode: cada personagem a partir da string corresponde a um nmero inteiro, do mesmo modo que a converso runes pode ser feito com: r: = [ ] Rune (s) O nmero de caracteres em uma string s dada por len ([ ] int (s)), mas utf8.RuneCountInString (s) mais rpido. A sequncia pode ser anexado a uma slice de bytes, como est: var b [ ]byte var s string b = append(b, s...) A alterao de um caractere em uma string
Strings so imutveis. Isto significa que quando str denota uma cadeia que str [ndice] no pode ser o lado esquerdo de uma atribuio: str [i] = 'D', onde i um ndice vlido d o erro no possvel atribuir a str [i] Para fazer isso, voc primeiro tem que converter a string para um array de bytes, em seguida, uma srie de itens de um determinado ndice pode ser alterado, e ento a array deve ser convertido de volta para uma nova cadeia. Por exemplo, altere "hello" para cello s:=hello c:=[ ]byte(s)
CURSO GRATUITO
c[0]=c s2:= string(c) / / S2 == "cello"
Por isso, claro que String-extraes so muito fceis com a sintaxe-slice. funo de comparao para arrays de bytes A funo 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 > b func 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 so iguais, exceto para uma possvel cauda switch { case len(a) < len(b): return -1 case len(a) > len(b): return 1 } return 0 / / Strings so iguais
Pesquisa e classificao so operaes muito comuns era biblioteca padro prev -los no tipo de pacote. Para classificar uma slice de ints, importar o pacote "sort" e simplesmente chamar os Ints funo 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 funes IntsAreSorted (a [ ]int) bool, que retorna verdadeiroo ou falso ou no a array classificada. Da mesma forma para Float64 elementos, voc usa a funo func Float64s(a [ ]float64) e para funo strings func Strings(a [ ]string). Para procurar um item em uma array ou uma slice, a array deve ser primeiro classificada (a razo que as funes de pesquisa so implementadas com o algoritmo binrio de busca).Em seguida, voc pode usar a funo func SearchInts(a [ ]int, n int) int, que procura n na slice a e retorna seu ndice. E, claro, as funes equivalentes para float64s e strings existem tambm: func SearchFloat64s(a [ ]float64, x float64) int func SearchStrings(a [ ]string, x string) int Mais detalhes podem ser encontrados na informao oficial: http:/ /golang.org/pkg/sort/ Esta a forma de utilizar as funes de tipo-package. Posteriormente descobrimos a teoria por trs disso, e vamos implementar ns mesmos a funcionalidade de classificao, bem como na embalagem.
Agora, temos a pea que faltava que precisvamos para explicar o projeto do append . A assinatura do append diferente do nosso costume. Esquematicamente, assim: func append(slice [ ]T, elements ...T) [ ]T
CURSO GRATUITO
onde T um espao reservado para qualquer tipo. Voc no pode realmente escrever uma funo em Go onde o tipo T determinado pelo chamador. por isso que append construdo 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 mo append, a array subjacente pode mudar. Este exemplo simples x := [ ]int{1,2,3} x = append(x, 4, 5, 6) fmt.Println(x) O mtodo de acrscimo muito verstil e pode ser utilizado para todos os tipos de manipulaes: 1) Append uma slice b para uma slice de um j existente: 2) Copie uma slice de um para uma novo slice b: 3) Eliminar o item no ndice i: 4) Corte do ndice i cultivam j de uma slice: 5) Estender uma slice com uma nova slice de comprimento j: 6) Inserir item no ndice x i: 7) Coloque um novo comprimento de slice j no ndice i: 8) Coloque uma slice b existente no ndice i: 9) Pop elemento mais alto da pilha: 10) Empurre um elemento x em uma pilha: a = append (a, b ...) b = make ([ ] T, len (a)) copy(b, a) a = append (a [: i], a [i +1:] ...) a = append (a [: i], a [j]: ...) a = append(a, make([ ]T, j)...) a = append(a[:i], append([ ]T{x}, a[i:]...)...) a = append(a[:i], append(make([ ]T, j), a[i:]...)...) a = append(a[:i], append(b, a[i:]...)...) x, a = a[len(a) -1], a[:len(a)-1] a = append(a, x)
Assim, para representar uma sequncia de elementos redimensionvel usar uma slice e a acrescentar operao. A slice muitas vezes chamado de um vetor em um contexto mais matemtica. Se isso torna o cdigo mais claro, voc pode definir um alias de vetor para o tipo de slice que voc precisa.
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 memria at que ele j no referenciado. Ocasionalmente, isso pode fazer com que o programa para armazenar todos os dados na memria quando necessria apenas uma pequena parte dela. Exemplo: esta funo FindDigits carrega um arquivo para a memria e procura -lo para o primeiro grupo de dgitos numricos 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 cdigo funciona como descrito, mas os retornados [ ] byte pontos em uma array que contm o arquivo inteiro. Uma vez que a slice de referencia da array original, enquanto a slice mantida em torno do coletor de lixo no pode libertar a array; poucos bytes teis do ficheiro de manter todo o contedo da memria. Para corrigir esse problema pode-se copiar os dados interessantes para uma nova slice antes de devolv-lo:
CURSO GRATUITO
func FindDigits(filename string) [ ]byte { b, _ := ioutil.ReadFile(filename) b = digitRegexp.Find(b) c := make([ ]byte, len(b)) copy(c, b) return c }
Maps
Tambm conhecida como uma array associativa, uma tabela hash ou um dicionrio, mapas so usados para pesquisar um valor pelo seu as - chave ciada. Muitos outros idiomas tm um tipo similar embutido. Por exemplo , Perl tem hashes , Python tem seus dicionrios e C + + tambm 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 so 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 nmeros inteiros , ponto flutuante e nmeros complexos, strings, ponteiros, interfaces (desde que o tipo dinmico apoia a igualdade), estruturas e arrays. As slices no pode ser usado como chaves de mapa, porque a igualdade no definido em cima delas. Mapas so um tipo especial de estrutura de dados: uma coleo 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 so tambm chamados associativo arrays ou dicionrios. Eles so ideais para pesquisar valores rpido: dada a chave, o valor correspondente pode ser recuperada rapidamente. O comprimento do mapa no tem que ser conhecida a declarao : um mapa pode crescer de forma dinmica .Como as slices, mapas contm referncias a uma estrutura de dados subjacente. Se voc passar um mapa para uma funo que altera o contedo do mapa, as mudanas sero visveis no chamador. Os mapas podem ser construdos usando a sintaxe literal composto de costume com pares chaves valor separados por dois pontos, por isso fcil de constru-los durante a inicializao.
Um mapa um tipo de referncia e declarou, em geral, como: var map1 map[keytype]valuetype var map1 map[string]int (Um espao permitido entre [KeyType] valuetype, mas gofmt remove essa) O comprimento do mapa no tem que ser conhecida a declarao: um mapa pode crescer de forma dinmica. O valor de um mapa no inicializada nulo. O tipo de chave pode ser qualquer tipo para o qual as operaes == e != So definidos, como string, int, float. Ento, arrays, slices e structs no 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 mtodo Hash ( ) Key( ) ou, de modo que uma tecla numrica 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 declarao de tipo . Mapas so baratos para passar para uma funo: 4 bytes em uma mquina de 32 bits, 8 bytes em uma mquina de 64 bits, no importa a quantidade de dados que possuem. Olhando -se um valor em um mapa chave rpido, muito mais rpido do que uma busca linear, mas ainda em torno de 100x mais lento do que a indexao 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 funo tambm pode ser usado como uma estrutura de ramificao: as teclas so usadas para selecionar o ramo que uma funo que executada. Se key1 um valor fundamental do mapa map1, ento map1[key1] o valor associado a key1, assim como a notao de array-index (uma array pode ser considerada como uma simples forma de um mapa, onde as chaves (Keys) so nmeros inteiros a partir de 0). O valor associado a key1 pode ser definido como val1 atravs da atribuio: map1 [key1] = val1 A atribuio v: = map1[key1] stores em v o valor correspondente ao key1, se key1 no est presente no mapa, em seguida, torna-se v o valor zero para o tipo de valor de map1.
CURSO GRATUITO
Len Como de costume (map1) d o nmero de pares no mapa, que pode crescer ou diminuir, porque mapa pares podem ser adicionados ou removidos durante a execuo. package main import fmt a number of maps are shown: func main( ) { var mapLit map[string]int / /var mapCreated map[string]float32 var mapAssigned map[string]int mapLit = map[string]int{one: 1, two: 2} mapCreated := make(map[string]float32) mapAssigned = mapLit mapCreated[key1] = 4.5 mapCreated[key2] = 3.14159 mapAssigned[two] = 3 fmt.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]) } Sada: Mapa literal em "um" : 1 Mapa criado em "key2" : 3,141590 Mapa atribudo em "dois" : 3 Mapa literal em "dez" : 0 mapList ilustra a utilizao do mapa literais: um mapa pode ser inicializado com a notao {key1: val1, key2: val2}, como arrays e estruturas. Os mapas so tipos de referncia: a memria alocada com a funo make: Inicializao de um mapa: var map1[keytype]valuetype = make(map[keytype]valuetype) ou curtu com: mapCreated feita da seguinte maneira: o que equivale a: map1 := make(map[keytype]valuetype) mapCreated := make(map[string]float) mapCreated := map[string]float{ }
Tambm mapAssigned uma referncia para o mesmo valor que mapLit, mudando mapAssigned tambm muda mapLit como mostra a sada do programa. !! No use new, use sempre make com mapas !! Observao: Se voc por engano atribuir um objeto de referncia com new ( ), voc recebe um ponteiro para uma referncia nula, o que equivale a declarar uma varivel no inicializada e tomando seu endereo: mapCreated := new(map[string]float) Ento ns comeamos na declarao: mapCreated[key1] = 4.5 o erro do compilador: operao invlida: 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 funo ( ) int como seu valor: package main import fmt f unc main( ) { mf := map[int]func( ) int{ 1: func( ) int { return 10 }, 2: func( ) int { return 20 }, 5: func( ) int { return 50 },
CURSO GRATUITO
} fmt.Println(mf) } A sada : mapa [01:00 x10903be0 05:00 x10903ba0 02:00 x10903bc0]: os inteiros so mapeados para endereos de funes.
capacidade Mapa
Ao contrrio de arrays, mapas dinamicamente crescer para acomodar novos valores -chave que so adicionados, eles no tm tamanho fixo ou mximo. 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 frequncia em Hz (medio de frequncias 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}
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 esto alguns exemplos que definem tais mapas: mp1 := make(map[int][ ]int) mp2 := make(map[int]*[ ]int)
Testando a existncia de key1 em map1: Vimos val1 = map1 [key1] nos devolve o val1 valor associado key1. Se key1 no existe no mapa, val1 torna-se o valor zero para o tipo do valor. Mas isso ambguo: agora no 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 formulrio vrgula 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 no 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 presena de uma chave e no se preocupam com o seu valor, voc poderia escrever: _, ok := map1[key1] / / ok == true se key1 est presente, caso contrrio, false Ou combinado com um caso: if _, ok := map1 [Key1]; ok { / / ... }
CURSO GRATUITO
Apagar um elemento com key1 de map1: Isto feito com: delete(map1, key1) Quando key1 no existe esta declarao no produz um erro. package main import 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) } } Sada: O valor de "Pequim" em mapa1 : 20 "Paris" em map1: falsa O valor : 0 mapa1 no contm Washington
Esta construo tambm 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 so variveis locais conhecidos apenas no corpo do para -assertion. O primeiro elemento em um mapa iterao escolhido random.If voc est interessado apenas nos valores, use o formulrio: for _, value := range map1 { ... }
CURSO GRATUITO
Para obter apenas as chaves, voc pode usar: for key := range map1 { fmt.Printf(key is: %d\n, key) } Exemplo: Listagem package main import 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) } } Sada: chave : 3 - valor : 3.000000 chave : 1 - valor : 1.000000 chave : 4 - valor : 4.000000 chave : 2 - valor : 2,000000 Vemos que um mapa no a chave-ordenada, nem ordenada pelos valores.
Suponha que ns queremos fazer uma slice de mapas, ento 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 verso A. O valor do item na verso B uma cpia do mapa de valor, de modo que os verdadeiroos mapa -variveis no inicializadas. package main import ( fmt ) func main( ) { / / Verso 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) / / Verso B: No bom! items2 := make([ ]map[int]int, 5) for _, item := range items2 { item = make(map[int]int, 1 / / Item apenas uma cpia do elemento slice. item[1] = 2 / / Este 'item' ser perdida na prxima iterao. } fmt.Printf(Version B: Value of items: %v\n, items2) }
CURSO GRATUITO
/ * Sada: 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[ ]] */ Classificando um mapa
Por padro um mapa isw no 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 main import ( 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]) } } / * Sada: 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
CURSO GRATUITO
/ Key: lima, Value: 98 / */ Mas se o que voc quer uma lista ordenada melhor voc usar uma slice de estruturas, que mais eficiente: type struct { key string value int }
Inverso um mapa
Com isto queremos dizer mudar os valores e as chaves. Se o tipo de valor de um mapa aceitvel como um tipo de chave, e os valores do mapa so nicos, isto pode ser feito facilmente: package main import ( 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) } } / * Sada: 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 no so nicos e, nesse caso no houver erro, mas o processamento do mapa invertido simplesmente pararam quando uma tecla no exclusivo encontrado, e ele provavelmente no Ir conter todos os pares a partir do original mapear! A soluo testar com cuidado para a singularidade e fazendo uso de um mapa de valores mltiplos, neste caso do tipo map[int] [ ]string
CURSO GRATUITO
The Go-distribuio contm mais de 150 padres embutidos pacotes para funcionalidades comuns, como a fmt, os,..., Como um todo, designada como a biblioteca de padro, para a maior parte (exceto algumas rotinas de nvel baixo) construdo no prprio Go. Eles esto documentados em: http:/ /golang.org/pkg/ Aqui vamos discutir o seu propsito geral de um nmero deles agrupados por funo, no vamos entrar em detalhes sobre a sua estrutura interna. O pacote de regexp.
No programa seguinte que deseja pesquisar um padro de strings pat em uma string Searchin. Testando se ocorrer o padro fcil, 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 padro, o que feito atravs da funo de compilao. Ento ns temos nossa disposio um nmero inteiro de match -, localizar e substituir-funes. Package main import ( fmt regexp strconv ) func main( ) { / / String para busca searchIn := John: 2578.34 William: 4567.23 Steve: 5632.18 pat := [0-9]+.[0-9]+ / / Padro 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 funo: str2 := re.ReplaceAllStringFunc(searchIn, f) fmt.Println(str2) } / * Sada: Match found! John: ##.# William: ##.# Steve: ##.# John: 5156.68 William: 9134.46 Steve: 11264.36 */ A funo de compilao tambm retorna um erro, que temos ignorado aqui com segurana, porque ns entramos no padro de ns mesmos e saber que uma expresso regular vlida. Se a expresso ser inserido pelo usurio ou tomada de uma fonte de dados, ento necessrio verificar este erro de anlise.
CURSO GRATUITO
Neste exemplo, tambm poderia ter usado o MustCompile funo que como compilao, mas entra em panic quando o padro no uma expresso regular vlida.
Em programas mais complexos diferentes partes da aplicao podem executar simultaneamente ou concomitantemente, pois isso tecnicamente chamado, geralmente por meio da execuo de cada parte do programa em um segmento diferente do sistema operacional. Quando estas partes diferentes partes e trabalhar com as mesmas variveis, os problemas mais provvel ocorrer: a ordem em que as variveis so compartilhados atualizao no podem ser previstos e, portanto, tambm os seus valores so imprevisveis! (Isso comumente chamado de condio de corrida:a corrida tpicos para as atualizaes das variveis). Este , naturalmente intolervel em um programa correto, ento como que vamos resolver este problema? A abordagem clssica deixar apenas um thread por vez mudar a varivel compartilhada: o cdigo em que a varivel alterada (o chamado seo crtica) bloqueado quando um segmento comea a executar, ento nenhuma outra thread pode comear com ele. Somente quando a thread em execuo terminar a seo um desbloqueio ocorre, ento outro segmento pode acess-lo. Em particular, o tipo de mapa que estudamos neste captulo no contm qualquer bloqueio interno para atingir esse efeito (o que deixado de fora por razes de performance), dito que o tipo de mapa no thread-safe. Ento, quando acessos simultneos acontecer a uma estrutura de dados mapa compartilhado, corrompido, o que significa no correta, os dados do mapa pode resultar. Em Go este tipo de bloqueio realizada com a varivel Mutex do pacote de sincronizao. sync vem sincronizado, aqui ou seja, os fios so sincronizados para atualizar a varivel (s) de forma ordenada. A sync.Mutex um bloqueio de excluso mtua: ela serve para proteger a entrada para a seo crtica do cdigo, de modo que apenas um thread pode entrar na seo crtica ao mesmo tempo. Suponha Informao uma varivel de memria partilhada, que deve ser guardado, em seguida, uma tcnica comum a de incluir um mutex nele, como: import sync type Info struct { mu sync.Mutex / / outros campos, como por exemplo Str string }
Uma funo que tem que mudar esta varivel poderia, ento, ser escrito como: funo Update (informaes * Informaes) { func Update(info *Info) { info.mu.Lock( ) / / Seo crtica: / / Fim da seo crtica 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 tambm 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 seo est bloqueado para escrever como com o Mutex normal. Ele tambm contm uma funo til once.Do (call),
CURSO GRATUITO
onde uma vez um variabole do tipo uma vez, o que garante que a chamada de funo s ser invocado uma vez, independentemente do nmero de uma vez. No (chamada) 's existem. Para situaes relativamente simples usando o bloqueio atravs do pacote de sincronizao para que apenas um thread por vez pode acessar a varivel ou o mapa Ir resolver este problema. Se isso retarda feito o programa muito ou provoca outros problemas, a soluo deve ser repensado com goroutines e canais em mente: esta a tecnologia proposta pelo Go para escrever aplicaes simultneas.
Sabemos que os clculos realizados por meio de programao, por vezes, no so precisos. Se voc usar o tipo float64 Go em ponto flutuante nmeros clculo, os resultados so precisos cerca de 15 dgitos decimais, o suficiente para a maioria das tarefas. Ao calcular com nmeros muito grandes de toda a gama dos tipos int64 ou UInt64 tambm pode ser muito pequeno. Nesse caso float32 ou float64 pode ser usado se a preciso no uma preocupao, mas se for, no podemos usar nmeros de ponto flutuante, porque eles s so representados por aproximao na memria. Para a realizao de clculos precisos perfeitamente com valores inteiros Go fornece o pacote grande, contida no pacote de matemtica: big.Int para inteiros e big.Rat para nmeros racionais (estes so nmeros que podem ser representados por uma frao como 2/5 ou 3.1416, mas no como nmeros Goracionais e ou ). Estes tipos podem conter um nmero arbitrrio de dgitos, limitada apenas pela memria disponvel da mquina. A desvantagem o maior uso da memria e da sobrecarga de processamento: so muito mais lento do que com o processo embutido inteiros. Um grande nmero inteiro construdo com a funo big.NewInt (n), onde n um int64, um grande nmero racional com big.NewRat (n, d) em que ambos n (o numerador) e d (o denominador) so do tipo int64. Porque Go no suporta sobrecarga de operador todos os mtodos das grandes tipos tm nomes, como Add ( ) e Mul ( ). So mtodos agindo sobre o inteiro ou racional como receptor, e na maioria dos casos, eles modificar o seu receptor e tambm retornar o receptor como resultado, de modo que as operaes podem ser acorrentado e memria guardada, porque nenhum big.Int temporria variveis tm que ser criada para conter resultados intermedirios. package main import ( fmt math math/big ) func main( ) { / / Aqui esto alguns clculos 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 esto alguns clculos 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) } / * Sada: Big Int: 43492122561469640008497075573153004 Rat Big: -37 / 112
CURSO GRATUITO
*/
Os pacotes so o principal meio de de organizar e compilar o cdigo. Agora vamos ver exemplos concretos do uso de pacotes que voc escreve sozinho. Nas prximas sees, vamos rever alguns pacotes da biblioteca padro. Por pacotes personalizados queremos dizer pacotes de auto -escrito ou de outra forma externa para a biblioteca padro. Ao escrever seus prprios pacotes, utilize, de uma nica palavra curta, nomes em minsculas, 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 diretrio atual contm o package_test.go programa. Ele usa cdigo 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 subdiretrio do nosso diretrio atual, por isso o vinculador liga o cdigo objeto do pacote (s), juntamente com o cdigo -objeto do programa principal. package pack1 var Pack1Int int = 42 var pack1Float = 3.14 func ReturnStr( ) string { return Hello main! } Exporta uma Pack1Int varivel int e um ReturnStr funo que retorna um string. Este programa no faz nada quando ele executado, uma vez que no contm um main ( ) funo. No principal programa package_test.go o pacote importado atravs da declarao import ./pack1/pack1 O formato geral da importao : import path or url to the package like import github.com/org1/pack1 Se um caminho relativo ao diretrio do pacote atual. package main import ( 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) } Sada: 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 no considerado uma boa prtica. A linha fmt.Printf ("Flutuar de package1:% f \ n", pack1.pack1Float), tentando acessar uma varivel ou funo no exportadas, nem sequer compilar. Ele d o erro:
CURSO GRATUITO
no pode referir-se o nome no exportadas pack1.pack1Float Os pacotes que so utilizados pelo principal programa deve ser construdo antes da compilao do programa principal. Cada exportado pack1-Item que usado no programa principal deve ser qualificado pelo nome do pacote: pack1.Item. Ento, por conveno, h uma estreita relao entre os subdiretrios e pacotes: cada pacote (todos os go-arquivos pertencentes a ele) reside em seu prprio subdiretrio, que tem o mesmo nome do pacote. Para maior clareza diferentes pacotes de residir em diretrios diferentes. Importe com: import . ./pack1" Ao utilizar. Como um alias, pode-se usar os itens do pacote, sem qualificao, com os seus nomes de 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 funes de inicializao so executados e variveis globais inicializadas. Importao 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 mquina com o comando vai instalar. Suponha que voc queira usar um pacote (fictcio) onde Code site poderia ser GoogleCode, github, bitbucket, barra de ativao ou outros;.. ext = a extenso, como com ou org, e goex o nome do pacote (muitas vezes estes comeam com movimento, de modo algum, uma conveno necessrio) Voc instala este com o comando: go install codesite.ext/author/goExample/goex Isso instala o cdigo no mapa codesite.ext / autor / goExample / goex menos de US $ GOROOT / src / Uma vez instalado, para import-lo em seu cdigo, use: import goex codesite.ext/author/goExample/goex Assim, o caminho de importao ser a URL acessvel via web para raiz do seu projeto seguido do subdiretrio. A execuo do programa comea com a importao dos pacotes, inicializar o package main e, em seguida, invocando a funo main ( ). Um pacote com nenhuma importao inicializado atravs da atribuio de valores iniciais para todas as suas variveis de nvel de pacote e, em seguida, chamar qualquer de nvel de pacote funo init ( ) definido na sua fonte. Um pacote pode conter inicializao mltipla (funes), mesmo dentro de um nico arquivo de origem; eles executam de forma no especificada. a melhor prtica se a determinao dos valores de um pacote s dependem de outros valores ou funes encontradas no mesmo pacote. Init ( ) funes no podem ser chamados. Pacotes importadas so inicializados antes da inicializao da prpria embalagem (com a exceo do principal), mas a inicializao de um pacote ocorre apenas uma vez na execuo de um programa. Construo e instalao de um pacote: include $(GOROOT)/src/Make.inc TARG=pack1 GOFILES=\ pack1.go\ pack1b.go\ include $(GOROOT)/src/Make.pkg E torn-lo executvel com chmod 777. / Makefile. A incluir declaraes puxar funcionalidade que detecta automaticamente a arquitetura da mquina 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 tambm copia pack1.a ao funcionrio 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 importao "pack1" em vez de importar "caminho para PACK1".
CURSO GRATUITO
A ferramenta GoDoc funciona tambm muito bom para mostrar os comentrios em seu prprio pacote: os comentrios devem comear com / / e precedem as declaraes (de pacotes, tipos, funes ...) sem linha em branco no meio. GoDoc produzir Ir produzir uma srie de pginas HTML, uma para cada arquivo de Go. Por exemplo: - No doc_example mapa temos a go-arquivos tipo e sortmain com alguns comentrios no arquivo tipo (os arquivos no precisa ser compilado); - Navegar na linha de comando para este mapa e comear o comando: GoDoc-http =: 6060-path = "." . ( o mapa atual, o sinalizador-caminho pode ser da forma / path/to/my/package1 onde o package1 mapa contm as fontes, ou aceitar uma lista de pontos (: caminhos) -separados; caminhos no enraizadas so relativos ao diretrio de trabalho atual. - Abra um navegador no endereo http:/ /localhost:6060 Voc, ento, ver a pgina GoDoc local com a esquerda a partir dos pacotes apontam um link para o seu mapa doc_example: doc_example | Packages | Commands | Specification Abaixo, est uma viso geral ordenada de links para a fonte e todos os objetos dentro dela (por isso bom para navegar e olhando para cima no cdigo fonte), juntamente com a documentao / comentrio: Package sort func Float64sAreSorted func IntsAreSortedfunc IsSortedfunc Sort func SortFloat64s func SortInts func SortStrings func StringsAreSorted type Float64Array func (Float64Array) Len func (Float64Array) Less func (Float64Array) Swap import doc_example documentao Pacote com GoDoc Se 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 contnuo documento a todos os membros da equipe. Com a-sync e-sync_minutes = n, voc pode at mesmo torn -lo automaticamente atualizar a documentao a cada n minutos! type IntArray func (IntArray) Len func (IntArray) Less func (IntArray) Swap type Interface type StringArray func (StringArray) Len func (StringArray) Less func (StringArray) Swap Other packages
Go instala a ferramenta de instalao de pacotes automtico do Go: ele instala pacotes, baix -los a partir de repositrios remotos atravs da internet, se necessrio 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 dependncias automaticamente. As dependncias dos pacotes que residem na submapas tambm so instalados, mas a documentao ou exemplos no so: eles so navegvel no site. A lista de todos os pacotes instalados podem ser encontrados em $ GOROOT / goinstall.log Ele usa o GOPATH varivel. Pacotes remotos: Suponha que deseja instalar o pacote marisma interessante (este contm uma srie de rotinas teis, consultehttp:/ /code.google.com/p/tideland -cgl/). Porque precisamos de criar direitos diretrio em algum submapas do Go -instalao, preciso emitir o comando como root ou su.
CURSO GRATUITO
Certifique-se de que as variveis Go-ambiente esto devidamente configuradas no .bashrc file para root. Instale com o comando: go install tideland -cgl.googlecode.com/hg Isso coloca o hg.a arquivo executvel 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 tambm hg.a num _obj submap. A partir de ento a funcionalidade do pacote pode ser usado no cdigo Go, usando por exemplo, como nome do pacote cgl, atravs da importao: import cgl tideland-cgl.googlecode.com/hg De Go 1 em diante vai instalar vai esperar caminhos de importao de cdigo do Google para ser da forma:" code.google.com / p / marisma-CGL ". Aps a atualizao para uma nova verso Go todos os binrios do pacote de pacotes instalados localmente so excludos. 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 lanamento contra o qual o pacote construir, aps Go 1 o suficiente para saber que era construir contra ela. go install tambm pode ser usado para compilar / link e instalar localmente seus prprios pacotes. Mais informaes podem ser encontradas em http:/ /golang.org.
A seguinte estrutura d-lhe um bom comeo (onde uc significa um nome de pacote geral; os nomes em negrito so os mapas, em itlico o executvel): / home / user / goprograms ucmain.go (main program for using package uc) Makefile (2makefile for ucmain) ucmain src/uc (contains go code for package uc) uc.go uc_test.go Makefile (1makefile for package) uc.a _obj uc.a _test uc.a (contains the estreitol executable files) ucmain pkg/linux_amd64 uc.a (object file of package) bin Coloque seus projetos em algum lugar em um mapa goprograms (voc pode criar uma varivel 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 uc import 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 uc
CURSO GRATUITO
import testing type ucTest struct { in, out string } var ucTests = [ ]ucTest { ucTest{abc, ABC}, ucTest{cvo-az, CVO-AZ}, ucTest{Antwerp, ANTWERP}, } 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 contedo: include $(GOROOT)/src/Make.inc TARG=uc GOFILES=\ uc.go\ include $(GOROOT)/src/Make.pkg Na linha de comando neste mapa de invocao: gomake Isso faz com mapa _obj e coloca o arquivo de pacotes compilados uc.a O pacote pode, em seguida, ser testado com: Go test Isso faz com que o _test mapa com uc.a nele, a sada d: PASS, de modo que os testes so OK. Observao: possvel que sua conta corrente no tem direitos suficientes para executar e instalar Go (permisso negada erro). Nesse caso, mude para o usurio root su. Certifique -se de que as variveis de ambiente, o caminho para o binrios tambm so definidos para su, como para a sua conta normal. Ento ns fazemos o nosso programa de partida principal como ucmain.go: package main import ( 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:
CURSO GRATUITO
TARG=ucmain GOFILES=\ ucmain.go\ include $(GOROOT)/src/Make.cmd Emisso gomake compila ucmain.go para ucmain. Correndo./ucmain gives: Usando o pacote uc!
Pacotes locais no mapa do usurio: 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 uc cd /home/user/goprograms/uc go install ./uc # build and install uc (= does same as previous command) cd .. go install . # build and install ucmain
Instalao 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,.. Ento v 1) cpia do cdigo fonte a US $ GOROOT/src/pkg/linux_amd64/uc 2) copiar o arquivo de pacotes para US $ GOROOT/pkg/linux_amd64/uc Ele pode ento ser importado em qualquer Go-source como: import uc OS cdigo 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 questes mais portabilidade da linguagem e do punho biblioteca padro. Voc poderia ter uma boa razo para escrever cdigo especfico da plataforma, como o suporte de linguagem de montagem. Nesse caso, razovel seguir esta conveno: prog1.go prog1_linux.go prog1_darwin.go prog1_windows.go define a interface de cdigo comum acima diferentes sistemas operacionais, e colocar o Cdigo especfico do sistema operacional em seu prprio Go -arquivo chamado prog1_os.go Para a ferramenta de Go ento voc pode especificar: prog1_$GOOS.go or prog1_$GOARCH.go ou no Makefile plataforma: prog1_$(GOOS).go\ or prog1_$(GOARCH).go\
CURSO GRATUITO
Ao iniciar um novo projeto ou a adio de novas funcionalidades a um projeto existente voc pode economizar tempo de desenvolvimento atravs da incorporao de um Go-biblioteca j existente em sua aplicao. Para fazer isso voc tem que entender a API (Application Programming Interface) da biblioteca, ou seja: quais mtodos voc pode chamar esta biblioteca e como cham-los. Poderia realmente ser possvel que voc no tem a fonte dessa biblioteca, mas os fabricantes, ento, certamente, tm 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 uma URL mais curta retornou como http:/ /goo.gl/O9SUO, que muito mais fcil de incorporar, por exemplo, em um servio como o twitter.Documentao para o servio urlshortener Google podem ser encontradas em http:/ /code.google.com.br / apis / urlshortener /. Google torna esta tecnologia disponvel para outros desenvolvedores como uma API que podemos chamar de nossas prprias aplicaes (grtis at um determinado limite). Eles tambm tm gerado um cliente de biblioteca Go para torn-lo ainda mais fcil. Observao: Google tornou a vida mais fcil para desenvolvedores Go para utilizar os seus servios, fornecendolhes os clientes Google API Go. Os programas de Go-cliente onde gerados automaticamente a partir do JSON-descrio 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 varivel GOPATH est definido em seu ambiente, porque o cdigo fonte externa ser baixado para o diretrio $ GOPATH / src e os pacotes tambm ser instalado neste diretrio $ 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/v1 go install Ir baixar o cdigo fonte, compilar e instalar o pacote. (Em Linux Ubuntu com 6g r60 9481 instalao funciona bem, o pacote instalado abaixo pkg / linux_amd64.) Um programa de internet para usar o servio urlshortener: Podemos agora usar o pacote instalado em nossos programas por import -lo e dar-lhe um apelido (para digitar menos): urlshortener importao "google-api-go-client.googlecode.com/hg/urlshortener/v1" Vamos agora escrever um aplicativo web, que mostra um formulrio 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 trs funes do identificador: o manipulador de raiz mostra a forma por meio da execuo do modelo de formulrio, 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 Mtodos
Go suporta tipos definidos pelo usurio ou personalizados na forma de tipos de alias ou estruturas. A struct tenta representar uma entidade do mundo real com suas propriedades.Estruturas so tipos compostos, para usar quando voc quer definir um tipo que consistem em uma srie de propriedades, cada um com seu prprio tipo e valor, agrupando pedaos de dados em conjunto. Em seguida, pode -se acessar os dados como se fosse parte de uma nica entidade. Eles tambm so tipos de valor e assim so construdos com a nova funo. As peas componentes de dados que constituem o tipo struct so 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 antirs sobre engenharia de software, foi chamado um registro em linguagens mais antigas como Cobol, e tambm existe sob o mesmo nome de struct no C-famlia de lnguas, nas linguagens OO como uma classe leve, sem mtodos. No entanto, porque Go no tem o conceito de uma classe, o tipo de estrutura tem um lugar muito mais importante em Go. O formato geral da definio de uma struct (estrutura) a seguinte: type identifier struct { field1 type1
CURSO GRATUITO
field2 type2 ... } Tambm type T struct {a, b} int a sintaxe legal, e mais adequado para estruturas simples. Os campos nesta struct tm nomes, como campo1, campo2, etc Se o campo no usado no cdigo, ele pode ser chamado _. Esses campos podem ser de qualquer tipo, mesmo instrui a si mesmos, funes ou interfaces .Porque um struct um valor, podemos declarar uma varivel do tipo struct, e dar os seus valores de campos, tais como: var s T s.a = 5 s.b = 8 Uma array pode ser visto como uma espcie de estrutura, mas com indexada ao invs de campos nomeados. Usando new: Memria para uma nova varivel struct alocado com a nova funo, que retorna um ponteiro para o armazenamento alocado: var t *T = new (T), que pode ser colocado em diferentes linhas, se necessrio (por exemplo, quando a declarao tem que ser escopo do pacote, mas a destinao no necessrio no incio): var t *T t = new(T) O idioma para escrever este mais curto : t := new(T), a varivel t um ponteiro para T: neste momento os campos contm os valores de zero de acordo com seus tipos. No entanto declarando var t T tambm aloca e zero inicializa memria para t, mas agora t do tipo T. Em ambos os casos t comumente chamado de uma instncia ou objeto do tipo T. package main import 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 padro (de modo% v) cpia impressa de um struct com fmt.Println ( ) mostra bem o seu contedo. Os campos podem ser dado um valor diferente, usando a notao de ponto, como costume em OO idiomas: structname.fieldname Os valores dos campos de struct pode ser recuperada com a mesma notao: structname.fieldname Isso chamado de um seletor no Go. Para acessar os campos de um struct, se a varivel do tipo struct ou um ponteiro para o tipo struct, usamos o mesmo seletor-notao: type myStruct struct { i int } var v myStruct / / v has struct type var p *myStruct / / p is a pointer to a struct
CURSO GRATUITO
v.i p.i Uma notao ainda mais curta ea forma idiomtica para inicializar uma instncia struct (uma estrutura literal) o seguinte: ms := &struct1{10, 15.5, Chris} / / Isto significa que ms do tipo * Struct1 var mt struct1 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 tambm pode inicializar valores precedendo-os com os nomes de campos. To novo (Tipo) e & Type { } so equivalentes expresses. Um exemplo tpico de um struct um tempo de intervalo (com incio e fim do tempo expresso aqui em segundos): type Interval struct { start int end int } E aqui esto algumas inicializaes: inter := Interval{0,3} inter2 := Interval{end:5, start:1} inter3 := Interval{end:5} (A) (B) (C)
No caso de (A) os valores indicados no literal deve ser exatamente na mesma ordem em que os campos so definidos na estruct, o e no obrigatria. Processo (B) mostra uma outra possibilidade que os nomes dos campos com um: preceder o valor, caso em que a sua sequncia no deve ser o mesmo, e os campos podem tambm ser omitido, como no caso de (C). A nomeao do tipo struct e seus campos adere regra Visibilidade, possvel que um tipo struct exportado tem uma mistura de campos: alguns exportados, outros no. A figura a seguir esclarece o layout de memria 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.struct1 O exemplo a seguir Listagem de 10,2 person.go mostra uma pessoa struct, um mtodo upPerson que tem um parmetro do tipo * Pessoa (de modo que o prprio objeto pode ser alterado!) E 3 formas diferentes de chamar esse mtodo: package main import ( fmt strings ) type Person struct { firstName lastName string string } func upPerson (p *Person) { p.firstName = strings.ToUpper(p.firstName) p.lastName = strings.ToUpper(p.lastName) }
CURSO GRATUITO
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) / / 2-estrutura como um ponteiro: pers2 := new(Person) pers2.firstName = Chris pers2.lastName = Woodward (*pers2).lastName = Woodward / / Esta tambm 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) } / * Sada: The name of the person is CHRIS WOODWARD The name of the person is CHRIS WOODWARD The name of the person is CHRIS WOODWARD */ caso 2, vemos que a definio de um valor atravs de um ponteiro como em pers2.lastName = "Woodward" funciona, no h nenhum operador -> necessrio como em C + +: Go faz a converso automaticamente. Note que tambm pode definir o valor por dereferencing o ponteiro: (*pers2).lastName = Woodward As estruturas e layout de memria: Estructs em Go e os dados neles contidos, mesmo quando um struct contm outras estruturas, formam um bloco contnuo de memria: isso d uma enorme vantagem de desempenho. Isso diferente em Java, com seus tipos de referncia, onde um objeto e seus objetos contidos podem estar em diferentes partes da memria, em Go este tambm 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 varivel struct um elemento de uma lista ligada ou uma rvore binria, comumente chamado de n. Nesse caso, o n contm links (os endereos) para os ns vizinhos; su para uma lista e le, ri para uma rvore so ponteiros para outra varivel Node. onde o campo de dados contm as informaes teis (por exemplo, um float64) e su aponta para o n sucessor; em Go-cdigo: type Node struct { data float64 su *Node } O primeiro elemento da lista chamada de cabea, ele aponta para o segundo elemento, o ltimo elemento chamado de cauda, ele no aponta para qualquer sucessor, ento seu campo su tem valor nulo. claro que em uma lista real, teramos muitos-ns de dados, a lista pode aumentar ou diminuir de
CURSO GRATUITO
forma dinmica. 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 su *Node } Aqui, cada n pode, no mximo, ter links para outros dois ns: o esquerdo (OE) e direita (ri); ambos podem propagar este projecto. O elemento de topo da rvore chamado de raiz, a camada inferior de ns que no tm mais ns abaixo deles so chamadas as folhas, um n licena tem valores nulos para os le -ri e ponteiros. Esse n uma rvore em si mesma, para que pudssemos escrever: em Go-cdigo: type Tree struct { le *Tree data float64 ri *Tree } Converso de estruturas: Como j vimos converso em Go segue regras rgidas. Quando temos um tipo struct e definir um tipo de alias para ele, ambos os tipos tm o mesmo tipo subjacente e podem ser convertidos um no outro, mas tambm observar os casos de compilao de erros que denotam atribuies impossveis ou converses: Listagem 10.3-struct_conversions.go: package main import fmt type number struct { f float32 } type nr number / / alias type func 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}
CURSO GRATUITO
O Go no suporta construtores como Java e C++, mas as funes de factory do como dos construtores so fceis de implementar. Muitas vezes, uma fbrica definida para o tipo de convenincia, por conveno um nome que comea com o novo ou nova. Suponha que definir um tipo struct arquivo:
Em seguida, a fbrica, 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 funo de fbrica. Um exemplo de cham-lo: f := NewFile(10, ./test.txt) Se arquivo definido como um tipo de estrutura, a expresses new(File) e &File{ } so equivalentes. Compare isso com as inicializaes desajeitados na maioria das linguagens OO: Arquivo Em geral podemos dizer que a fbrica 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 instncia na memria, use: tamanho: = unsafe.Sizeof (T { }) Como forar o uso do mtodo de fbrica: Aplicando a regra de Visibilidade, podemos forar o uso do mtodo de fbrica e proibGo o uso novo, efetivamente tornando o nosso tipo particular, como chamado em idiomas orienbtadas a objetos. package matrix type matrix struct { ... } function NewMatrix(params) *matrix { m := new(matrix) / / M inicializado return m } Por causa da m de array, precisamos usar o mtodo de fbrica em outro pacote: package main import matrix ... wrong := new(matrix.matrix) / / no Ir compilar (array privado) right := matrix.NewMatrix(...) / / a nica maneira de instanciar uma array new ( ) e maker ( ) revisitado para mapas e estruturas:
CURSO GRATUITO
At agora temos visto 2 dos 3 tipos para os quais fazem ( ) pode ser usado: slices / maps / channels
Para ilustrar a diferena de comportamento para os mapas e os possveis erros, experincia com o seguinte programa: package main type Foo map[string]string type Bar struct { thingOne string thingTwo int } func main( ) { / / OK: y := new(Bar) (*y).thingOne = hello (*y).thingTwo = 1 / / No OK: z := make(Bar) / / erro de compilao. 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 / / no OK: u := new(Foo) (*u)[x] = goodbye / / !! panic !!: erro de execuo: Atribuio de entrada in nil map (*u)[y] = world }
Para tentar fazer ( ) uma varivel struct no to ruim, o compilador comea o erro, mas newing um mapa e tentar preench-lo com dados d um erro de tempo de execuo! new(Foo) um ponteiro para um nulo, ainda no atribudo, mapa: que deve ter muito cuidado com isso! pacote personalizado usando estruturas package structPack type ExpStruct struct { Mi1 int Mf1 float } Exemplo: package main import ( fmt ./struct_pack/structPack ) func main( ) { struct1 := new(structPack.ExpStruct) struct1.Mi1 = 10
CURSO GRATUITO
struct1.Mf1 = 16. fmt.Printf(Mi1 = %d\n, struct1.Mi1) fmt.Printf(Mf1 = %f\n, struct1.Mf1) } Sada: Mi1 = 10 MF1 = 16.000000
Um campo em um struct pode, alm de um nome e um tipo, tambm, opcionalmente, um tag: este um fio ligado ao campo, que poderia ser de documentao ou algum outro rtulo importante. O contedotag no pode ser usado na programao normal, apenas o pacote refletir pode acess -lo. package main import ( fmt reflect ) type TagType struct { field1 bool field2 string field3 int }
/ / tags An important answer The name of the thing 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) } / * Sada: An important answer The name of the thing How much there are * /
campos annimos e estruturas incorporados s vezes pode ser til ter estruturas que contm um ou mais campos annimos (ou embutidos), ou seja campos com nenhum nome explcito. Apenas o tipo de tal campo obrigatrio e, em seguida, o tipo tambm o seu nome. Tal campo annimo tambm pode ser em si uma estrutura: estruturas podem conter estruturas incorporadas. Isso se compara vagamente ao conceito de herana nos OO -lnguas e, como veremos, pode ser usado para simular um comportamento muito parecido com herana. Isto obtido pela incorporao ou composio, por isso, podemos dizer que na composio de Go favorecido sobre herana. package main
CURSO GRATUITO
import fmt type innerS struct { in1 int in2 int } type outerS struct { b int c float32 int / / anonymous field innerS / / anonymous field } 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) } Sada: outer.b : 6 outer.c : 7.500000 outer.int : 60 outer.in1 : 5 outer.in2 : 10 outer2 : {6 7,5 60 5 {10}} Para armazenar dados em um campo annimo ou ter acesso aos dados que usamos o nome do tipo de dados: outer.int,a conseqncia que s podemos ter um campo annimo de cada tipo de dados em uma struct.
estruturas Embarcadas
Como uma estrutura tambm um tipo de dados, ele pode ser utilizado como um campo annimo, 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 'herana' fornece uma maneira de obter algum ou todos os seus implementao de outro tipo ou tipos. package main import 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)
CURSO GRATUITO
fmt.Println(b.A) } Sada: 1234 {1 2} Mtodos Estruturas parecer uma forma simples de aulas, portanto, um programador OO pode perguntar: onde esto os mtodos da classe? Novamente Go tem um conceito com o mesmo nome e aproximadamente o mesmo significado: um mtodo Go uma funo que atua sobre varivel de um determinado tipo, o chamado receptor. Assim, um mtodo um tipo especial de funo. O tipo de receptor pode ser (quase) qualquer coisa, no apenas um tipo struct: qualquer tipo pode ter mtodos, at mesmo um tipo de funo ou de alias tipos para int, bool, strins ou array. O receptor tambm no pode ser um tipo de interface, uma vez que uma interface a definio abstrata e um mtodo a implementao, tentando faz-lo gera o erro do compilador: tipo de receptor invlido ... Estreitolmente, no pode ser um tipo de ponteiro, mas pode ser um indicador para qualquer um dos tipos permitidos. A combinao de um (struct) tipo e seus mtodos o equivalente Go de uma classe em OO. Uma diferena importante que o cdigo para o tipo e os mtodos de ligao a ela no so agrupados juntos, eles podem existir em diferentes ficheiros de origem, a nica exigncia que eles tm de estar no mesmo pacote. A coleo de todos os mtodos em um determinado tipo T (ou * T) chamado o conjunto mtodo de T (ou * T). Mtodos so funes, por isso novamente no h nenhuma sobrecarga de mtodo: para um determinado tipo, no existe apenas um mtodo com um determinado nome. Mas, com base no tipo de receptor, no h sobrecarga: um mtodo 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) Matrix func (a *sparseMatrix) Add(b Matrix) Matrix Tambm um apelido para um determinado tipo no tem os mtodos definidos nesse tipo. O formato geral de um mtodo : func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... } O receptor especificado em ( ) antes do nome do mtodo aps a palavra -chave funo. Se recv a instncia receptor e Method1 o nome do mtodo, ento a chamada ou a invocao do mtodo segue o tradicional objeto.mtodo seletor de notao: recv.Method1( ) Nesta expresso se recv um ponteiro, ento ele automaticamente desreferenciado. Se o mtodo no 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-lnguas, mas em Go no h nenhuma palavra -chave especificada para ele; se voc gosta voc pode usar auto ou este como o nome para a varivel do receptor, mas voc pode escolher livremente. Aqui est um exemplo simples de mtodos em uma struct: package main import 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( ))
CURSO GRATUITO
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 { Sada: A soma : 22 Adicione-os e param: 42 A soma : 7 package main import fmt type IntVector [ ]int func (v IntVector) Sum( ) (s int) { for _, x := range v { s += x } return } func main( ) { fmt.Println(IntVector{1, 2, 3}.Sum( )) }
/ / Output: 6
Um mtodo e o tipo em que ele atua devem ser definidos no mesmo pacote, por isso que voc no pode definir mtodos de tipo int, float ou similar. Tentar definir um mtodo em um tipo int d o erro do compilador:Por exemplo, se voc deseja definir o mtodo a seguir em time.time: func (t time.Time) first3Chars( ) string { return time.LocalTime( ).String( )[0:3] } Voc obtm o mesmo erro para um tipo definido em outro, portanto, tambm no-local, pacote. Mas h uma maneira de contornar: voc pode definir um alias para esse tipo (int, float, ...) e, em seguida, definir um mtodo para esse tipo. Ou incorporar o tipo como um tipo annimo em uma nova estrutura, como no exemplo a seguir. claro que este mtodo , ento, s vlido para o tipo de alias. Listagem 10.12-method_on_time.go: package main import ( 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( ))} / * Sada: Full time now: Mon Oct 24 15:34:54 Romance Daylight Time 2011 First 3 chars: Mon
CURSO GRATUITO
*/
Um mtodo pode alterar os valores (ou o Estado) da varivel receptor desde que seja um ponteiro, como o caso de funes (a funo tambm pode alterar o estado de seu parmetro quando este passado como um ponteiro: chamada por referncia ). !! No se esquea do ( ) depois Method1, ou voc recebe o erro de compilao: method is not an expression, must be called !! O receptor tem de ter um nome explcito, e este nome deve ser utilizado no mtodo. receiver_type chamado de (receptor) tipo base, este tipo deve ser declarado dentro do mesmo pacote que todos os seus mtodos. Em Go os mtodos anexados a um (receptor) tipo no so escritos dentro da estrutura, como o caso de classes; o acoplamento muito mais solta: a associao entre o mtodo eo tipo estabelecida pelo receptor. Mtodos no so misturados com a definio de dados (as estruturas): eles so ortogonais aos tipos; representao (dados) e comportamento (mtodos) so independentes.
recv mais freqentemente um ponteiro para a receiver_type por motivos de desempenho, isso especialmente verdadeiroo quando o tipo de receptor um struct. Deestreito o mtodo em um tipo de ponteiro se voc precisar do mtodo para modificar os dados dos pontos de recepo para. Caso contrrio, muitas vezes mais limpa para definir o mtodo em um tipo de valor normal. Isso ilustrado no exemplo a seguir pointer_value.go: mudana ( ) recebe um ponteiro para B, e muda o seu campo interno; write ( ) s mostra o contedo da varivel B e recebe o seu valor por cpia. Anncio no main ( ) que vai faz trabalho de canalizao para ns, ns mesmos no temos que descobrir se a chamar os mtodos em um ponteiro ou no, Go faz isso para ns. b1 um valor e b2 um ponteiro, mas as chamadas mtodos funcionam muito bem. package main import ( 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( )) } / * Sada: {1} {1}
CURSO GRATUITO
*/
Tente fazer write ( ) alterar o seu valor receptor b: voc vai ver que ele compila bem, mas o b original no alterado! Vimos que um mtodo no 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 mtodo em Point3: func (p Point3) Abs( ) float { 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 mtodo por valor e por isso copiado, mas vlido Go. Neste caso, o mtodo tambm pode ser chamado de um ponteiro para o tipo (h desreferncia automtica). Suponha p3 definido como um ponteiro: p3 := &Point3{ 3, 4, 5 } Depois, voc pode escrever p3.Abs( ) instead of (*p3).Abs( ) E um mtodo com um tipo de receptor *TwoInts like AddThem ( ) pode ser chamado em um valor do tipo enderevel TwoInts, no h engano automtica. Assim two2.AddThem ( ) pode ser usado em vez de (&two2).AddThem( ) Mtodos em valores e ponteiros chamada: Pode haver mtodos ligados ao tipo, e outros mtodos anexados a um ponteiro para o tipo. Mas no importa:. Se para um tipo T um mtodo Meth( ) existe em *T e t uma varivel do tipo T, ento t.Meth ( ) automaticamente traduzido para o (& t).Meth( ) Mtodos de ponteiro e valor tanto pode ser chamado em valores de ponteiro ou no -ponteiro, este ilustrado no programa seguinte, onde a lista de tipo tem um mtodo Len ( ) sobre o valor e um mtodo Append ( ) em um ponteiro para lista, mas , vemos que ambos os mtodos podem ser chamados de variveis de ambos os tipos. package main import ( fmt ) type List [ ]int func (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) }
Mtodos e campos no-exportados Considere o comeo de uma pessoa no pacote person2.go: o tipo de pessoa claramente exportado, mas os seus campos no so! Por exemplo, a declarao 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 tcnica bem conhecida de OO -idiomas: proporcionar getter- e mtodos setters FirstName e setFirstName. Para o mtodo setter que usamos o conjunto de prefixo, para o mtodo getter s usamos o nome do campo.
CURSO GRATUITO
package person type Person struct { firstName lastName }
string string
func (p *Person) FirstName( ) string { return p.firstName } func (p *Person) SetFirstName(newName string) { p.firstName = newName } Outro Exemple: package main import ( fmt ./person )
func main( ) { p := new(person.Person) / / Erro: p.FirstName indefinido / / (No pode se referir ao campo no exportadas ou mtodo nome) / / P.FirstName = "Eric" p.SetFirstName(Eric) fmt.Println(p.FirstName( )) / / Output: Eric } Acesso concorrente aos objetos: No deveria ser possvel 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 simultneos seguro voc pode usar os mtodos da sincronizao de pacotes.
Quando um tipo annimo incorporado em uma estrutura, os mtodos visveis desse tipo so incorporados como bem de fato, o tipo externa herda os mtodos: 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 herana encontrada em OO-lnguas clssicas, mas tambm muito anlogo aos mixins de Ruby. Aqui est um exemplo ilustrativo: suponha que temos um tipo de interface do motor, e um carro tipo struct que contm um campo annimo de Motor: type Engine interface { Start( ) Stop( ) } type Car struct { Engine } Poderamos, ento, construir o seguinte cdigo: func (c *Car) GoToWorkIn {
CURSO GRATUITO
/ / Pega no car c.Start ( ); / / Unidade de trabalho c.Stop ( ); / / Sair do car } No seguinte exemplo completo method3.go mostrado que um mtodo em um struct incorporado pode ser chamado diretamente em uma instncia do tipo de incorporao. package main 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 mtodos de um tipo existente em um outro tipo: mtodos associados com o campo annimo so promovidos para tornar -se mtodos do tipo delimitador. claro que um tipo pode ter mtodos que actuam apenas sobre as variveis desse tipo, e no em variveis do 'pai' tipo incorporado. Tambm substituindo (assim como com campos) implementado para mtodos: um mtodo no tipo de incorporao com o mesmo nome de um mtodo 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 vrios tipos annimos, temos na verdade uma verso simples de herana mltipla, como em: type Child struct { Father; Mother } Estruturas incorporao estruturas do mesmo pacote tem acesso total a um dos campos e mtodos mais. Como incorporar a funcionalidade em um tipo
Existem basicamente duas maneiras de fazer isso: A agregao (ou composio): incluir um campo chamado do tipo da funcionalidade desejada B Incorporao: 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 contm uma mensagem acumulada ( claro que isso poderia
CURSO GRATUITO
ser elaborado). Se voc quiser equipar todos os seus tipos de domnio com uma capacidade de registro, voc implementa tal Log e adicion -lo como um campo para o seu tipo, bem como um mtodo de Log ( ) retornar uma referncia a este registo. Exemplo parte A package main import ( fmt ) type Log struct { msg string } type Customer struct { Name string log *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 } / * Sada do log: 1 Minha Vida 2 - Depois de mim, o mundo ser um lugar melhor! */ Exemplo parte B package main import ( fmt ) type Log struct { msg string } type Customer struct { Name string Log } func main( ) {
CURSO GRATUITO
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 } / * Sada: Minha Casa Log: {1 Minha Vida 2 - Depois de mim, o mundo ser um lugar melhor}! */ O tipo embutido no precisa um ponteiro, o cliente no precisa de um mtodo Add mais, porque ele usa o mtodo de Log, o Cliente pode ter seu prprio String-mtodo e usando nela a sequncia log ( ) mtodo. Isto tambm funciona se o tipo incorporado em si incorpora um outro tipo, e os mtodos do tipo incorporado pode ser usado directamente pelo tipo de incorporao. Assim, uma boa estratgia construir pequenas tipos reutilizveis como uma caixa de ferramentas para a composio dos prprios tipos de domnio.
Herana mltipla
Herana mltipla a capacidade de um tipo para obter os comportamentos de mais de uma classe pai. Em linguagens OO clssicos que normalmente no implementada (excees so 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 necessrios 'pai' do tipo em construo. 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 mtodo pertence ao tipo de telefone, eo segundo ao tipo de cmera. A incorporao de ambos os tipos resolve o problema, como ilustrado no seguinte programa: package main import fmt type Camera struct { } func (c *Camera) TakeAPicture( ) string { return Click } type Phone struct { } func (p *Phone ) Call( ) string { return Ring Ring } / / Herana mltipla type 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( ))
CURSO GRATUITO
fmt.Println(It works like a Phone too: , cp.Call( )) } / * Sada: Our new CameraPhone exhibits multiple behaviors ... It exhibits behavior of a Camera: Click It works like a Phone too: Ring Ring */
Na programao uma srie de operaes bsicas aparecem uma e outra vez, como abertura, fechamento, leitura, escrita, classificao, etc Alm disso, eles tm um significado geral para eles: abertura pode ser aplicado para um arquivo, uma conexo de rede, uma conexo de banco de dados , etc Os detalhes da implementao so em cada caso muito diferente, mas a idia geral a mesma. Em Go esta aplicada extensivamente na biblioteca padro, atravs da utilizao de interfaces , em que tais mtodos genricos obter nomes cannicos como Open ( ), Read ( ), Write ( ), etc Se voc quiser escrever idiomtica Go , voc deve seguir esta conveno, dando a seus mtodos, onde os mesmos nomes e as assinaturas apropriadas como esses mtodos "cannicos". Isso faz com que o software Go mais consistente e legvel. Por exemplo: se voc precisa de um mtodo convert-to-string, nome o String ( ) e no ToString ( ).
Mtodos em linguagens OO como C + +, Java, C # ou Ruby so definidas no contexto de classes e herana: quando um mtodo chamado em um objeto, o tempo de execuo v se o seu minrio de classe qualquer de suas superclasses ter uma definio para esse mtodo, caso contrrio, resultar em uma exceo. Em Go tal uma hierarquia de herana no de todo necessrio: se o mtodo definido para esse tipo pode ser invocado, independente de haver ou no o mtodo existe para outros tipos, por isso, nesse sentido, h uma maior flexibilidade. GO no exigem uma definio de classe explcita como Java, C + +, C #, etc fazer. Em vez disso, uma "classe" implicitamente definido, fornecendo um conjunto de mtodos que operam em um tipo comum. Este tipo pode ser um struct ou qualquer outro tipo definido pelo usurio. Por exemplo: dizer que gostaria de definir o nosso prprio tipo Integer para adicionar algumas possveis mtodos para trabalhar com nmeros inteiros, como um tostring -converso. Em Go que definiria isso como: type Integer int func (i *Integer) String( ) string { return strconv.Itoa(i) } Em Java ou C # o tipo ea funo seriam colocados juntos em um Integer classe; no Ruby voc pode simplesmente escrever o mtodo do tipo int bsica. Resumido: em Go tipos so basicamente classes (dados e mtodos associados). GO no sabe como herana linguagens OO orientada classe. Herana tem duas vantagens principais: a reutilizao de cdigo e polimorfismo. A reutilizao de cdigo em Go conseguido atravs da composio e da delegao, e polimorfismo atravs do uso de interfaces: ele implementa o que s vezes chamado de programao de componentes. Muitos desenvolvedores dizem que as interfaces da Go fornecer um comportamento polimrfico mais potente e ainda mais simples do que a herana de classe. Observao: Se voc realmente precisa de mais recursos de OO, d uma olhada no pacote gosma ("Go Programao Orientada a Objetos") de Scott Pakin (https:/ /github.com/losalamos/goop): fornece Go com
CURSO GRATUITO
objetos de estilo JavaScript (objetos com base em prottipo), mas suporta herana mltipla e expedio, dependente do tipo de modo que voc provavelmente pode implementar a maioria de suas construes favoritas de outras linguagens de programao. A String ( )-mtodo e formato especificadores para um tipo
Quando voc define um tipo com uma srie de mtodos, as chances so que voc vai querer fazer uma seqncia de caracteres de sada personalizada para ele com uma String (mtodo), em outras palavras: uma sada legvel e impresso. Isto porque se string ( ) definido por um determinado tipo, ento este mtodo ser utilizado em fmt.Printf ( ) para produzir o padro de sada: o que produzido com o especificador de formato % v Tambm fmt.Print ( ) e fmt.Println ( ) usar automaticamente o mtodo ( ) da cadeia. package main import ( 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 tambm que o especificador de formato %T nos d a especificao do tipo completo % # v nos d uma sada completa da instncia com seus campos (que tambm pode ser til na gerao de cdigo de programao Go). Observao: No cometa o erro de definir String ( ) em termos de si mesmo, como no seguinte snippet. Em seguida, o programa faz uma recurso infinita (TT.String ( ) chama fmt.Sprintf que chama TT.String ( ) ...) e rapidamente d um erro de falta de memria: type TT float64 func (t TT) String( ) string { return fmt.Sprintf(%v, s) } t.String( )
CURSO GRATUITO
O desenvolvedor Go no tem que codificar a liberao de memria para as variveis e estruturas que no so mais utilizados no programa. Um processo separado no tempo de execuo Go, o coletor de lixo, cuida disso. Ele comea agora e ento, procura por variveis que no so mais indicados e libera essa memria. Funcionalidade em relao a este processo pode ser acessado atravs do pacote de tempo de execuo. 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 memria so escassos, um grande pedao de memria puderam ser imediatamente libertado nesse ponto na execuo, ea programa pode ter uma reduo momentnea no desempenho (por causa do processo de coleta de lixo). Se voc quiser saber o estado da memria atual, use: fmt.Printf(%d\n, runtime.MemStats.Alloc/1024) Suponha que uma ao especial deve ser tomado imediatamente antes de um objeto obj removido da memria, como escrever para um arquivo de log. Isto pode ser conseguido chamando a funo: runtime.SetEstreitolizer(obj, func(obj *typeObj)) onde func(obj * typeObj) uma funo que leva um ponteiro -parmetro do tipo de obj que executa a ao adicional. funo tambm pode ser uma funo annima. SetEstreitolizer no 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.
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/formulrio para a interao com os usurios de seu sistema. Contudo, podemos Go mais a fundo e tambm imaginar os objetos de nossa aplicao interagindo uns com os outros. Estes, por sua vez, precisam se conhecer para ento saber que mensagens podero trocar. a que entram as interfaces. Alm das j citadas interaes com usurio e entre objetos, programas inteiros tambm podem se comunicar e peas de hardware precisam se encaixar perfeitamente. Com isso, fica fcil imaginar diversas situaes para o uso de interfaces. Podemos visualizar os objetos de nossa aplicao como instncias de uma classe na memria e dividi -los em duas partes: sua visualizao externa e a prpria implementao de seus mtodos. Vamos ento 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 podero ter certeza de que as mensagens enviadas a ele sero correspondidas. E o mais importante: sabero quais operaes podero ser solicitadas. Tente fazer uma relao desses objetos com um programa e sua interface grfica. A inteno do desenho de um formulrio a de mostrar quais operaes podem ser executadas sobre tal aplicao. 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 mtodo chamado, j sabemos previamente quais os seus parmetros e seu tipo de retorno. Se declararmos uma varivel em nosso cdigo, estaremos certos de que poderemos chamar qualquer mtodo disponibilizado pelo objeto que a ela for associado. Ou seja, declarar uma classe que implementa X significa dizer que todos os mtodos dessa interface X estaro presentes para Y. Como podemos entender uma interface X ou Y poderia ter ainda diversos outros mtodos prprios . Neste ponto, j podemos apontar uma grande utilidade para esse conceito. Imagine a implementao de um grande sistema. Quando dois programadores ou pares iniciam a codificao de mdulos separados e interligados, eles podem estabelecer previamente um contrato de comunicao. Deste modo, quem programa o mdulo A, saber que o mdulo B implementa a interface X, portanto, ter certeza das mensagens que podero ser enviadas. E mais importante do que isso, ter cdigo compilvel e receber ajuda do tipo code insight ao manipular os fontes. Mas o que h de to especial em IInterface? At o momento, a nica utilidade prtica das interfaces est na garantia de que determinados mtodos esto presentes nas classes. Veja que conseguimos driblar a falta da herana mltipla 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 programao orientada a objetos. Diferentemente da herana mltipla, que muito difcil de ser implementada e controlada.
CURSO GRATUITO
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 implementao. Go no uma linguagem OO "clssico": ele no sabe o conceito de classes e herana. Uma interface define um conjunto de mtodos (o conjunto do mtodo), mas estes mtodos no contm cdigo: eles no so implementados (eles so abstratos). Tambm uma interface no pode conter variveis. Uma interface declarado no formato: type Namer interface { Method1(param_list) return_type Method2(param_list) return_type ... } onde Namer um tipo de interface. O nome de uma interface formada pelo nome do mtodo, 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 no to apropriado) acabar com poder como na recupervel, ou para inici-lo com um I (Mais como in. NET ou Java). Interfaces em Go so curtos, eles geralmente tm de 0 mximo trs mtodos. Ao contrrio da maioria das linguagens OO, em interfaces de Go pode ter valores, uma varivel do tipo de interface ou um valor de interface: var ai Namer ai uma estrutura de dados multiword com um valor no inicializado de zero. Allthough no completamente a mesma coisa, que , em essncia, um ponteiro. Ento ponteiros para fazer a interface valores so ilegais, pois eles seriam completamente inteis e dar origem a erros no cdigo. Sua mesa de mtodo ponteiros construir atravs da capacidade de execuo reflexo. Tipos (como estructs) pode ter o conjunto mtodo da interface implementada, a aplicao contm para cada cdigo verdadeiroo mtodo de como agir em uma varivel desse tipo: eles implementam a interface, o conjunto mtodo constitui a interface desse tipo. Uma varivel de um tipo que implementa a interface pode ser atribuda a ai (o valor do receptor), ento o mtodo de mesa tem ponteiros para os mtodos de interface implementadas. Ambos de mudana de curso, quando uma varivel de outro tipo (que tambm implementa a interface) atribudo a ai. Um tipo no tem que declarar explicitamente que implementa uma interface: interfaces so satisfeitas de forma implcita. Vrios tipos podem implementar a mesma interface. Um tipo que implementa uma interface pode tambm ter outras funes. Um tipo pode implementar vrias interfaces. Um tipo de interface pode incluir uma referncia a uma instncia de qualquer um dos tipos que implementam a interface (Uma interface tem o que chamado um tipo dinmico). Mesmo que a interface foi definida mais tarde do que o tipo, em um pacote diferente, compilados separadamente: se o objeto implementa os mtodos citados na interface, em seguida, ele implementa a interface. Todas estas propriedades permitem uma grande flexibilidade. package main import fmt type Shaper interface { Area( ) float32 type 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 declarao separada: / / areaIntf := Shaper(sq1) / /Ou ainda:
CURSO GRATUITO
areaIntf := sq1 fmt.Printf(The square has area: %f\n, areaIntf.Area( )) } Sada: O quadrado tem rea: 25.000000
O programa define uma estrutura quadrada e um Shaper interface, com um mtodo Area( ). Em main( ) uma instncia de Praa construda. Fora da principal, temos um mtodo Area( ) com um tipo de receptor de Square, onde a rea de um quadrado calculado: a struct Square implementa o Shaper interface. Devido a isso, podemos atribuir uma varivel do tipo Square para uma varivel do tipo de interface: areaIntf = sq1 Agora, a varivel de interface contm uma referncia para a varivel Square e atravs dela podemos chamar o mtodo Area( ) em Square. Claro que voc pode chamar o mtodo imediatamente na instncia Square sq1.Area( ), mas a novidade que podemos cham-lo na instncia interface, assim generalizando a chamada. A varivel de interface contm tanto o valor do exemplo receptor e um ponteiro para o mtodo adequado de uma tabela mtodo. Esta a verso de Go de polimorfismo, um conceito bem conhecido em software OO: o mtodo correto escolhido de acordo com o tipo de corrente, ou colocar de outra forma: um tipo parece apresentar comportamentos diferentes quando associada a diferentes instncias. Se Square no teria uma implementao de Area ( ), gostaramos de receber o erro de compilador muito clara: no pode usar sq1 (type *Square) como tipo Shaper na atribuio: *Square no implementar Shaper (faltando mtodo Area) O mesmo erro ocorreria se Shaper tinha outro mtodo Permetro( ), e da Praa no teria uma implementao para que, mesmo que Permetro ( ) no foi chamado em uma instncia Square. Sabemos expandir o exemplo com um retngulo tipo que tambm implementa Shaper. Podemos agora fazer uma array com elementos do tipo Shaper, e mostrar polimorfismo em ao, usando um para a faixa nele e chamando Area ( ) em cada item: Listagem 11.2-interfaces_poly.go: package main import 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 retngulo precisa de um valor q := &Square{5 / / Area ( ) da Square (Praa) 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])
CURSO GRATUITO
fmt.Println(Area of this shape is: , shapes[n].Area( )) } } / * Sada: Looping through shapes for area ... Shape details: {5 3} Area of this shape is: 15 Shape details &{5} Area of this shape is: 25 */
No ponto de chamar formas [n]. Area ( )) s sabemos que este um objeto Shaper, sob a capa "morphs" em um quadrado ou um retngulo e se comporta de acordo. Talvez agora voc pode comear a ver como as interfaces podem produzir um cdigo mais limpo, mais simples e mais escalvel. Aqui est um outro exemplo mais concreto: temos 2 tipos stockPosition e carro, ambos tm um mtodo getValue ( ); percebendo que podemos definir uma interface valiosa com este mtodo. E o que podemos definir mtodos que levam um parmetro do tipo valioso e que so utilizados por todos os tipos que package main import fmt type stockPosition struct { ticker string sharePrice float32 } / * Mtodo para determinar o valor de uma posio de estoque * / func (s stockPosition) getValue( ) float32 { return s.sharePrice * s.count } type car struct { make string model string price float32 } / * Mtodo para determinar o valor de um carro * / func (c car) getValue( ) float32 { return c.price } / * Contrato que define as coisas diferentes que tm valor * / type valuable interface { getValue( ) float32 } / * Qualquer coisa que satisfaa 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) } /* Sada: Value of the asset is 2308.800049 Value of the asset is 66500.000000 */
CURSO GRATUITO
Um exemplo da biblioteca padro: O pacote io contm um tipo de interface do Leitor: type Reader interface { Read(p [ ]byte) (n int, err error) } Se definirmos a r varivel como: var r io.Reader em seguida, o seguinte o cdigo correto: r = os.Stdin r = bufio.NewReader(r) r = new(bytes.Buffer) f, _ := os.Open(test.txt) r = bufio.NewReader(f) porque o lado direito objetos cada implementar um mtodo Read( ) com a mesma assinatura exata. O tipo esttico de r io.Reader. Observao: Por vezes, a interface de palavra tambm utilizada de um modo ligeiramente diferente: visto a partir do ponto de vista de um determinado tipo, a interface desse tipo o conjunto de mtodos exportados definidos para o tipo, sem que tenha de ser um tipo de interface explcita definido com estes mtodos. Interface do incorporao (s)
Uma interface pode conter o nome de um (ou mais) outra interface (s), o que equivale a enumerar explicitamente os mtodos da interface incorporado na interface contendo. Por exemplo a interface do arquivo contm todos os mtodos de ReadWrite e bloqueio, alm de um mtodo Close ( ). type ReadWrite interface { Read(b Buffer) bool Write(b Buffer) bool } type Lock interface { Lock( ) Unlock( ) } type File interface { ReadWrite Lock Close( ) }
Uma varivel de tipo de interface varivel pode conter um valor de qualquer tipo, preciso ter um meio de detectar este tipo dinmico, que o tipo real do valor armazenado na varivel em tempo de execuo. O tipo de dinmica pode variar durante a execuo, mas sempre atribudo ao tipo da prpria varivel interface. Em geral, podemos testar se Vari contm em um determinado momento uma varivel do tipo T com o teste de assertion tipo:
CURSO GRATUITO
v := varI.(T) / / Assertion tipo desmarcada vari deve ser uma varivel de interface, se no o compilador sinaliza o erro: invlido varI.(T) (tipo no de interface (type of varI) esquerda) A assertion tipo pode no ser vlido, o compilador faz o mximo possvel para ver se a converso vlida, mas no pode prever todos os casos possveis. Se essa converso falhar durante a execuo do programa de um erro de execuo ocorre! A maneira mais segura usar a seguinte forma: if v, ok := varI.(T); ok { / / Verificado type assertion Process(v) return } / / varI no do tipo T Se essa converso vlida, v Ir conter o valor da varivel convertidos para o tipo T e ok ser verdadeiroa, caso contrrio, v o valor zero para T e ok falsa, ento no h erro de execuo ocorre! ! Sempre use a vrgula, forma ok para o tipo afirmaes! Na maioria dos casos voc gostaria de testar o valor de ok em um caso, ento, mais conveniente usar a forma: if v, ok := varI.(T); ok { / / ... } Nesta forma de sombreamento a varivel 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 varivel de interface tambm 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 varivel t recebe valor e tipo de areaIntf. Todos os tipos listados (exceto nil) tm de implementar a interface (Shaper, neste caso), se o tipo atual nenhum dos casos-tipos, a clusula default executado. Fallthrough no permitido. Com um type -switch uma anlise do tipo de tempo de execuo pode ser feito. Claro que todos os tipos internos como int, bool e string tambm pode ser testado em um switch tipo. Se voc s precisa testar o tipo switch. e no precisa do valor, a atribuio pode ser deixado de fora, como: switch areaIntf.(type) { case *Square: fmt.Printf(Type Square %T with value %v\n, t, t)
CURSO GRATUITO
case *Circle: fmt.Printf(Type Circle %T with value %v\n, t, t) ... default: fmt.Printf(Unexpected type %T, t) } No seguinte trecho de cdigo de uma funo tipo classificador mostrado que aceita uma array com um nmero varivel 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) { 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 #%ds type is unknown\n, i) } } } Quando se tratar de dados de tipo desconhecido de testes de fontes externas tipo e converso para tipos Go de dados pode ser muito til, por exemplo, a anlise de dados que so 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 funes de impresso verificar se o tipo pode imprimir -se. Uma interface uma espcie de contrato que o tipo de execuo. Interfaces descrever o comportamento de tipos, o que eles podem fazer. Eles completamente separar a definio do que um objeto pode fazer a partir de como ele faz isso, permitindo implementaes distintas de se fazer representar em momentos diferentes pela mesma varivel de interface, que o polimorfismo essencialmente. Escrevendo funes para que eles aceitar uma varivel de interface como parmetro torna mais geral.! Use interfaces para tornar seu cdigo de aplicao mais geral! Isso tambm aplicado onipresente no cdigo da biblioteca padro. impossvel compreender como construir sem uma boa compreenso do conceito de interface.
vimos que os mtodos de variveis na verdade no fazem distino 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 no enderevel, mas felizmente os flags do compilador um erro no uso inadequado.Considere o seguinte programa: package main import (
CURSO GRATUITO
fmt ) type List [ ]int func (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) } } 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: / / No pode usar lst type List) como tipo Appender no argumento da funo: / / Lista de no implementar Appender (Append mtodo requer ponteiro / / CountInto (lst, 1, 10) if LongEnough(lst) / / VLIDO: tipo de receptor Idntico fmt.Printf(- lst is long enough) } / / Um valor de ponteiro plst := new(List) CountInto(plst, 1, 10) / / VLIDO: tipo de receptor Idntico if LongEnough(plst) { / / VLIDO: a lista * pode ser desreferenciado para o receptor fmt.Printf(- plst is long enough) / / - Plst2 longa enoug } } Discusso: 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 mtodo em uma interface, ele deve ou ter um tipo de receptor idntico ou deve ser diretamente perceptvel a partir do tipo de concreto: P mtodos de ponteiro pode ser chamado com ponteiros. mtodos de Valor pode ser chamada com valores. mtodos Valor receptor pode ser chamada com valores de ponteiro, pois eles podem ser desreferenciado primeiro. mtodos Pointeiro receptor no pode ser chamada com valores, no entanto, porque o valor armazenado dentro de uma interface no tem endereo. Ao atribuir um valor a uma interface, o compilador garante que todos os possveis mtodos de interface pode realmente ser chamado nesse valor, e, assim, tentar fazer uma atribuio indevida falhar na compilao.
/ / Receptor)
CURSO GRATUITO
Um bom exemplo vem da prpria biblioteca Go, ou seja, o tipo de pacote. Para classificar uma coleo de nmeros e strings, voc s precisa do nmero de elementos Len( ), uma maneira de comparar itens i e j Less(i, j) e um mtodo para trocar itens com ndices i e j de swap(i, j ) A funo Ordenar em espcie tem um algoritmo que utiliza apenas estes mtodos em um conjunto de dados de coleta (para implement-lo, usamos aqui uma espcie de bolha, mas qualquer tipo algoritmo poderia ser utilizado.): 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 parmetro geral de um classificador tipo de interface que declara esses mtodos: type Sorter interface { Len( ) int Less(i, j int) bool Swap(i, j int) } O tipo int em Sorter no significa que os dados de cobrana deve conter ints, I e J so ndices inteiros, e o comprimento tambm um inteiro. Agora, se queremos ser capazes de classificar um array de inteiros, tudo o que precisamos fazer definir um tipo e implementar os mtodos da interface: type IntArray [ ]int func (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 cdigo para chamar a funcionalidade de classificao 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 sort sort.Sort(a) O cdigo completo de trabalho podem ser encontrados em sort.go e sortmain.go. Para ilustrar o poder do conceito, o mesmo princpio aplicado para uma variedade array of floats, de strings, e uma array de estruturas dayArray que representam os dias da semana. package sort type Sorter interface { Len( ) int Less(i, j int) bool Swap(i, j int) } func Sort(data Sorter) { for pass:=1; pass < data.Len( ); pass++ {
CURSO GRATUITO
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 } } return true } / / Tipos convenintes para os casos comuns type IntArray [ ]int func (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 [ ]string func (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 [ ]string func (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 func StringsAreSorted(a [ ]string) bool { return IsSorted(IntArray(a)) } { return IsSorted(StringArray(a)) }
Continuando: package main import ( 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)
CURSO GRATUITO
} 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 } 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( ) } Sada: 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 Observao: panic ("falha") uma maneira de parar o programa em uma situao que no poderia ocorrer em circunstncias comuns ; que tambm poderia ter impresso uma mensagem e, em seguida, usado os.Exit (1) . Este exemplo nos deu uma melhor viso do significado e uso de interfaces. Para classificar os tipos primitivos, sabemos que no temos de escrever esse cdigo ns mesmos, a biblioteca padro fornece para isso. Para a classificao geral do pacote de classificao define a type Interface interface { Len( ) int Less(i, j int) bool Swap(i, j int) }
CURSO GRATUITO
que resume os mtodos abstratos necessrios para a classificao, a func Sort (interface de dados) que pode atuar em tal tipo. Estes podem ser usados na execuo de triagem para outros tipos de dados. Na verdade isso exatamente o que ns fizemos no exemplo acima, a utilizao deste para ints e strings, mas tambm para uma dayArray tipo definido pelo usurio, para classificar uma array interna de strings.
A leitura ea escrita so atividades universais em software: a leitura e gravao de arquivos vem mente em primeiro lugar, a leitura ea escrita de buffers (por exemplo, slices de bytes ou a strings), e para a entrada padro, fluxos de sada e de erro, conexes de rede, tubos, etc, ou para os nossos prprios tipos personalizados. Para fazer com que a base de cdigo o mais genrico possvel, 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 mtodos Read( ) e Write( ), necessria 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 mtodo com assinatura, Read([ ]byte)(int, error). O mtodo Read( ) l os dados do objeto que ele chamado em e coloca os dados lidos na slice byte dado. Ele retorna o nmero de bytes lidos e um objeto de erro que ser nulo se no houve erro, ou io.EOF ("fim de arquivo") se no houve erro e ao estreitol da entrada foi atingido, ou algum outro no -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 mtodo com assinatura, Write ([ ] byte)(int, error)). O mtodo Write( ) grava dados da slice byte dado no objeto o mtodo foi chamado, e retorna o nmero de bytes escritos e um objeto de erro (que ser nulo se no houve erro). Readers e Writers io so unbuffered, o pacote bufio prev as correspondentes operaes de buffer e por isso so especialmente teis para ler e escrever arquivos UTF -8 texto codificado. Atravs da utilizao, tanto quanto possvel essas interfaces na assinatura de mtodos, eles se tornam o mais genrico possvel: cada tipo que implementa essas interfaces pode usar esses mtodos. Por exemplo, a funo que implementa um decodificador JPEG tem um leitor como um parmetro, e, portanto, pode decodificar a partir do disco, conexo de rede, http compactado, etc
interface vazio
A interface vazia ou mnima no tem mtodos e assim no faz qualquer exigncia em tudo. type Any interface{ } Assim, qualquer varivel, qualquer tipo implementa-lo (e no apenas os tipos de referncia como o objeto em Java / C #), e qualquer ou Qualquer realmente um bom nome como apelido e abreviao! ( anlogo ao objeto de classe em Java e C #, a classe base de todas as classes, assim Obj tambm se encaixa.) A varivel desse tipo de interface de var val interface{ } pode atravs de atribuio receber uma varivel de qualquer tipo: package main import fmt var i = 5 var str = ABC type Person struct { name string
CURSO GRATUITO
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 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: 5 val has the value: ABC val has the value: &{Rob Pike 55} Type pointer to Person main.Person Um int, uma string e uma instncia a Person atribudo a uma varivel val interface. Um teste de switch-type para seu tipo. Cada interface { } varivel ocupa duas palavras na memria: 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 funo lambda: package main import fmt type specialString string var 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!) } }
CURSO GRATUITO
testFunc(whatIsThis) } func main( ) { TypeSwitch( ) } Construindo uma array de um tipo geral ou com variveis 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 ns mesmos? Se queremos agora sabemos que isso possvel usando a interface vazia, vamos dar -lhe o elemento apelido: type Element interface { } Em seguida, deestreito um vetor struct, que contm 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 mtodo At( ) que retorna o elemento om: func (p *Vector) At(i int) Element { return p.a[i] } E uma funo 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 afirmaes do tipo. O compilador rejeita as alegaes garantidos a falhar, mas digitar afirmaes sempre executar em tempo de execuo e por isso pode gerar erros de tempo de execuo!
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 no funciona, o compilador lhe d o erro: no possvel usar dataSlice (type [ ]myType) como type [ ]interface { } in assignment A razo que o layout de memria de ambas as variveis no o mesmo.A cpia deve ser feito explicitamente com uma declarao de alcance, como em: var dataSlice [ ]myType = FuncReturnSlice( ) var interfaceSlice [ ]interface{ } = make([ ]interface{ }, len(dataSlice)) for ix, d := range dataSlice { interfaceSlice[i] = d }
CURSO GRATUITO
No encontramos dados-estruturas como listas e rvores, usando um tipo struct recursiva chamado de n. Os ns continha um domnio de um determinado tipo de dados. Agora, com a interface vazio nossa disposio, os dados podem ser do mesmo tipo, e podemos escrever cdigo genrico. Aqui est um cdigo de partida para uma estrutura de rvore binria: a definio geral, uma newNode mtodo para a criao de uma estrutura to vazia, e um SetData mtodo para dar os dados de um valor: package main import fmt type Node struct { le *Node 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 tambm pode ser atribuda a um outro valor de interface, enquanto o valor de base implementa os mtodos necessrios. Esta converso verificado em tempo de execuo, e quando falha ocorre um erro de tempo de execuo: este um dos aspectos dinmicos do Go, comparvel a linguagens dinmicas como Ruby e Python. Suponha que: var ai AbsInterface / / Declara mtodo Abs ( ) type SqrInterface interface { Sqr( ) float } var si SqrInterface pp := new(Point) / / Dizer * Ponto implementa Abs, Sqr var empty interface{ } Em seguida, as seguintes declaraes e afirmaes do tipo so vlidos: empty = pp; / / Tudo satisfaz vazio ai = empty.(AbsInterface); / / Valor subjacente pp implementa Abs ( ) / / (Insuficincia de tempo de execuo de outra forma) si = ai.(SqrInterface); / / * Point tem Sqr( ) mesmo que no AbsInterface empty = si; / / * Ponto implementa conjunto vazio / / Nota: estaticamente verificvel ento digite assertion no necessrio. Aqui est um exemplo com uma chamada de funo: type myPrintInterface interface {
CURSO GRATUITO
print( ) } func f3(x myInterface) { x.(myPrintInterface).print( ) / / Tipo de assertion para myPrintInterface } A converso para myPrintInterface totalmente dinmico: ele vai trabalhar, desde que o tipo subjacente de x (o tipo dinmico) define um mtodo de impresso. A reflexo sobre estructs
Algumas das possibilidades de estructs so demonstrados, Vemos que NumField( ) d o nmero de campos na estrustruct, com um loop for, podemos passar por cada um deles indexado por I com Field(i).Podemos tambm chamar seus mtodos, por exemplo, o mtodo n onde n o ndice com: package main import ( fmt reflect ) type NotknownType struct { s1, s2, s3 string func (n NotknownType) String( ) string { return n.s1 + - + n.s2 + - + n.s3 } / / Varivel 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 mtodo, que String ( ): results := value.Method(0).Call(nil) fmt.Println(results) / / [Ada - Go - Oberon] } / * Sada: main.NotknownType struct Field 0: Ada Field 1: Go Field 2: Oberon [Ada - Go - Oberon] */ Mas se tentar mudar um valor, temos um erro de execuo: panic: reflect.Value.SetString using value obtained using unexported field. Assim, vemos que somente os campos exportados (comeando com uma letra maiscula) de um struct so ajustveis, o que demonstrado: package main
CURSO GRATUITO
import ( 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++ { 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) } / * Sada: 0: A int = 23 1: B string = skidoo t is now {77 Sunset Strip} * /]
Printf e reflexo.
Os recursos do pacote de reflexo discutido na seo anterior so muito utilizadas na biblioteca padro, por exemplo, a funo 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 reflexo 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, no existe %u ou %ld, somente %d. Esta tambm a forma de Print e Printf pode imprimir os argumentos bem sem uma seqncia de formato. Para tornar isso mais concreto, vamos implementar uma verso simplificada de tal funo print -generic no exemplo a seguir, que usa uma chave do tipo de deduzir o tipo, e de acordo com esta imprime a varivel fora . package main import ( os strconv ) type Stringer interface { String( ) string } type Celsius float64 func (c Celsius) String( ) string { return strconv.FormatFloat(float64(c),f, 1, 64) + C } type Day int var dayName = [ ]string{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday} func (day Day) String( ) string { return dayName[day]
CURSO GRATUITO
} 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( ) { print(Day(1), was, Celsius(18.36)) } tipagem dinmica em Go
Em linguagens clssicas (como C + +, Java e C #) de dados e os mtodos que agem sobre os dados esto unidos no conceito de classe: a classe contm os dois, eles no podem ser separados. Em Go no h classes: dados (estruturas ou tipos mais gerais) e mtodos so tratados ortogonalmente, eles so muito mais flexveis. Interfaces em Go so semelhantes aos seus homlogos Java / C #: tanto especificar um conjunto mnimo de mtodos que um implementador de uma interface deve fornecer. Mas eles tambm so mais fluidas e genrica: qualquer tipo que fornece o cdigo para os mtodos de uma interface implicitamente implementa essa interface, sem ter que dizer explicitamente que ele faz. Em comparao com outras lnguas Go o nico que combina os valores de interface, verificao de tipo esttico (no um tipo de implementar a interface?), Converso de tempo de execuo dinmica e nenhuma exigncia para declarar explicitamente que um tipo satisfaz uma interface. Essa propriedade tambm permite que as interfaces a ser definido e usado sem ter que modificar o cdigo existente. Uma funo que tem um (um ou mais) parmetro de um tipo de interface pode ser chamado com uma varivel cujo tipo implementa essa interface. Tipos de implementao de uma interface pode ser passado para qualquer funo que leva essa interface como um argumento. Isto assemelha-se muito mais o duck typingin em linguagens dinmicas como Python e Ruby, o que pode ser definido como significando que os objetos podem ser manipulados (por exemplo, passagem por funes), com base nos mtodos que prestam, independentemente de seus tipos reais: o que so menos importante do que podem ser. Isto ilustrado na duck_dance.go programa, onde a funo DuckDance leva uma varivel de tipo de interface IDuck. O programa s compila quando DuckDance for chamado em uma varivel de um tipo que implementa IDuck.
package main import 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( ) {
CURSO GRATUITO
fmt.Println(I am quacking!) } func (b *Bird) Walk( ) { fmt.Println(I am walking!) } func main( ) { b := new(Bird) DuckDance(b) } Sada: I am quacking! I am walking! I am quacking! I am walking! I am quacking! I am walking! Se o tipo de pssaro no entanto no implementar Walk( ) (coment -lo), ento temos um erro de compilao: no pode usar b (type *Bird) como tipo IDuck no argumento da funo: * Bird no implementar IDuck (faltando mtodo Walk) Se chamarmos o DuckDance function ( ) para um gato, Go d um erro do compilador, enquanto Python ou Ruby terminar em um erro de execuo! invocao de mtodo dinmico No entanto, em Python, Ruby e similares pato digitao realizada como ligao tardia (durante a execuo): mtodos so chamados simplesmente nesses argumentos e variveis e resolvidas em tempo de execuo (que na sua maioria tm mtodos como responds_to para verificar se o objeto sabe este mtodo, mas isso equivale a mais de codificao e teste). Pelo contrrio, em Go s necessidades de execuo (na maioria das vezes) fica estaticamente verificados pelo compilador: ele verifica se um tipo implementa todas as funes de uma interface quando houver cesso de uma varivel para uma varivel desse interface. Se a chamada de mtodo est em um tipo geral como interface { }, voc pode verificar se a varivel implementa a interface, ao fazer uma type assertion. Como um exemplo, suponha que voc tem diferentes entidades representadas como tipos que tm de ser escritos como fluxos XML. Em seguida, vamos definir uma interface para XML escrever com o mtodo 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 funo para o streaming de qualquer varivel, testando com uma type assertion, se a varivel passada implementa a interface, se no chamamos a sua prpria funo encodeToXML para fazer o trabalho: / / Exportados funo de streaming XML. {func StreamXML(v interface{ }, w io.Writer) error { if xw, ok := v.(xmlWriter); ok { / / uma xmlWriter, mtodo de uso do tipo afirmou. return xw.WriteXML(w) } / / Na implementao, por isso temos de usar a nossa prpria funo (com talvez reflexo): return encodeToXML(v, w) } / / Funo de codificao XML interno. func encodeToXML(v interface{ }, w io.Writer) error {
CURSO GRATUITO
/ / ... } 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 prpria para codificar e descodificar os dados de e para fluxos de bytes, caso contrrio a maneira padro com reflexo usado. Ento Go oferece as vantagens de uma linguagem dinmica, mas no as suas desvantagens de erros em tempo de execuo. Isto alivia para uma parte da necessidade de testes de unidade, que muito importante em linguagens dinmicas, mas tambm apresenta uma quantidade considervel de esforo. Go as interfaces promove separao de interesses, melhora a reutilizao de cdigo, e torna mais fcil para construir sobre os padres que emergem como o cdigo se desenvolve. Com interfaces Go do padro de injeo de dependncia tambm pode ser implementado.
Um padro de refatorao que muito til a extrao de interfaces, reduzindo assim o nmero de tipos e mtodos necessrios, 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 vrios objetos que todos tm o mesmo comportamento, e um desenvolvedor deseja abstrato que o comportamento, eles podem criar uma interface e, em seguida, usar isso. Suponha que ns 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 mtodo de classificao ( ): package main import 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 {
CURSO GRATUITO
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( )) } } / * Sada: Looping through shapes for area ... Shape details: {5 3} Area of this shape is: 15 Shape details: &{5} Area of this shape is: 25 Looping through topgen for rank ... Shape details: {5 3} Topological Genus of this shape is: 2 Shape details: &{5} Topological Genus of this shape is: 1 */ Ento voc no tem que trabalhar todas as suas interfaces de fora antes do tempo; todo o projeto pode evoluir sem invalidar decises iniciais. Se um tipo deve implementar uma nova interface, o prprio tipo no tem que ser mudado, necessrio apenas fazer o novo mtodo (s) do tipo.
Se voc deseja que os tipos de uma interface explicitamente declaram que implement -lo, voc pode adicionar um mtodo com um nome descritivo para o mtodo set da interface. Por exemplo: type Fooer interface { Foo( ) ImplementsFooer( ) } Um tipo Bar deve, ento, implementar o mtodo ImplementsFooer ser um Fooer, documentar claramente o fato. type Bar struct{ } func (b Bar) ImplementsFooer( ) { } func (b Bar) Foo( ) { } A maioria dos cdigos no fazer uso de tais restries, j que eles limitam a utilidade da idia de interface. s vezes, porm, eles podem ser necessrios para resolver as ambiguidades entre as interfaces semelhantes.
Em vimos que a sobrecarga de funo no permitida. Em Go isso pode ser feito por meio de um nmero varivel de parmetros com ... T como ltimo parmetro. Se tomarmos T para ser a interface vazia,
CURSO GRATUITO
e sabemos que uma varivel de qualquer tipo satisfaz T, ento isso nos permite passar qualquer nmero de parmetros de qualquer tipo para essa funo, que o que a sobrecarga meios. Este aplicado na definio da funo: fmt.Printf(format string, a ...interface{ }) (n int, errno error), itera esta funo mais a slice de descobrir o tipo de seus argumentos de forma dinmica. Para cada tipo parece se uma String ( ) implementado, em caso afirmativo, isto usado para produzir a sada.
A herana de interfaces
Quando um tipo inclui (incorporaes) outro tipo (que implementa uma ou mais interfaces) como um ponteiro, em seguida, o tipo pode usar todas as interfaces de mtodos. 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 mtodo Log( ), ento uma tarefa task de Task pode cham -lo: type ReaderWriter struct { *io.Reader *io.Writer } Os princpios acima so aplicadas em todos os Go-pacotes, maximing, assim, a possibilidade de utilizao de polimorfismo e minimizando a quantidade de cdigo. Este considerado um importante as melhores prticas em Go-programao. Interfaces de teis podem ser detectados quando o desenvolvimento j est em andamento. fcil adicionar novas interfaces, porque os tipos existentes no tem que mudar (eles s tm de implementar os seus mtodos). Funes existentes podem, em seguida, ser generalizados de ter um parmetro (s) de um tipo restreito a um parmetro do tipo de interface: muitas vezes apenas a assinatura da funo 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.
Muitas vezes, quando voc tem um struct em seu aplicativo, voc tambm precisa de uma coleo de (ponteiros para objetos) de que struct, como: type Any interface{ } type Car struct { Model string BuildYear / / ... int } type Cars [ ]*Car
CURSO GRATUITO
Podemos, ento, usar as funes de alta ordem usando o fato de que as funes podem ser argumentos na definio da funcionalidade necessria, como por exemplo: 1) na definio de um processo geral ( ) funo, que se assume uma funo f que opera em todos os carros: / / Processar todos os cars com a funo dada f: func (cs Cars) Process(f func(car *Car)) { for _, c := range cs { f(c) } } 2) construir sobre isso, certifique-Encontrar-funes 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 critrio. 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) }) Ns tambm pode retornar funes com base em argumentos. Talvez a gente gostaria de acrescentar carros para colees baseadas nos fabricantes, mas esses podem ser variados.Assim, definimos uma funo para criar uma funo especial de acrescentar, bem como um mapa de colees: 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 funo: appender := func(c *Car) {
CURSO GRATUITO
if _, ok := sortedCars[c.Manufacturer]; ok { sortedCars[c.Manufacturer] = append(sortedCars[c. Manufacturer], c) } else { sortedCars[Default] = append(sortedCars[Default], c) } } return appender, sortedCars }
Ns agora podemos us-lo para resolver os nossos carros em colees individuais, como em: manufacturers := [ ]string{Ford, Aston Martin, Land Rover, BMW, Jaguar} sortedAppender, sortedCars := MakeSortedAppender(manufacturers) allUnsortedCars.Process(sortedAppender) BMWCount := len(sortedCars[BMW]) Fazemos este trabalho cdigo na seguinte cars.go programa (aqui ns mostramos apenas o cdigo em main ( ), o resto do cdigo j foi mostrado acima: / / .. tipos e funes func 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 [padro: [0xf840003ba0] Jaguar: [ ] Land Rover: [ ] BMW: [0xf840003bd0 0xf840003b70] Aston Martin: [ ] Ford: [0xf8400038a0] ] Temos 2 BMWs Alm da FMT pacotes e os, tambm vamos precisar importar e usar o bufio pacote para entrada e sada de buffer.
CURSO GRATUITO
Como podemos ler entrada do usurio a partir do teclado (console)? A entrada lido a partir do teclado ou a entrada padro, que os.Stdin. A forma mais simples utilizar o Sscan -famlia de digitalizao e de funes do fmt pacote, como ilustrado neste programa: / / L a entrada do console: package main import fmt var ( firstName, lastName, s string i int f float32 input = 56.12 / 5212 / Go format = %f / %d / %s ) 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 padro, armazenando valores separados por espaos sucessivos em argumentos sucessivos, que interrompe a digitalizao em uma nova linha.Scanf faz o mesmo, mas usa o seu primeiro parmetro como formato de cadeia para ler os valores das variveis. Sscan e amigos funcionam da mesma maneira, mas ler a partir de uma cadeia de entrada como ao invs da entrada padro. Voc pode verificar o nmero de itens lidos e se o erro quando algo d errado. Mas tambm pode ser feita com um leitor tamponada do bufio pacote, como demonstrado no seguinte programa: package main import ( 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 padro de entrada: = inputReader := bufio.NewReader(os.Stdin). O construtor bufio.NewReader ( ) tem a assinatura: func NewReader(rd io.Reader) *Reader Ele toma como argumento qualquer objeto que satisfaz a interface io.Reader (qualquer objeto que tem uma leitura adequada e retorna um novo io.Reader tampo que l a partir do leitor de dado, satisfaz este requisito os.Stdin . O leitor tem um mtodo ReadString(delim byte), em que l a entrada at ser encontrado, delim ser includo, lido colocado em um buffer. ReadString retorna a seqncia de leitura zero para o erro, quando ele l at o estreitol de um arquivo, a leitura string retornada e io.EOF; se delim no for encontrado: error err != nil is returned.
CURSO GRATUITO
No nosso caso, a entrada do teclado lido at que a tecla ENTER (que contm '\ n') aproveitado. Os.Stdout da sada padro a tela; os.Stderr onde erro de informao pode ser escrito, em sua maioria igual a os.Stdout. Em cdigo Go normal as declaraes var so omitidos e as variveis so 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-verses diferentes: package main import ( 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!) } / / Verso 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) } / / Verso 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 so diferentes!
Leitura de um arquivo
Arquivos em Go so representados por ponteiros para objetos do tipo os.File, tambm chamado filehandles. O os.Stdin entrada padro e sada os.Stdout usamos na seo anterior so ambos do tipo *os. package main
CURSO GRATUITO
import ( 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 } 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 varivel 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 funo Open para os: este aceita um nome de arquivo de parmetro 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 no existe ou o programa no 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 ento aplicar bufio.NewReader para obter uma varivel 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 nvel, 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 mtodo ReadString ('\ n') ou ReadBytes ('\ n'). Observao: Em um exemplo anterior, vimos-arquivos de texto em Unix estreitol em \n, mas no Windows \r\n. Ao utilizar o mtodo ReadString ou ReadBytes com \n como um delimitador que voc no tem que se preocupar com this.The uso do ReadLine ( ) mtodo tambm poderia ser uma boa alternativa. Quando li o arquivo aps o estreitol ento readerError != Nil o loop for deixada atravs da instruo de retorno. (Na verdade io.EOF verdade), e Algumas alternativas: 1) Ler o contedo de um arquivo inteiro em uma string: Se isso suficiente para que voc precisa, voc pode usar o mtodo ioutil.ReadFile ( ) do pacote io/ioutil, que retorna um byte [ ] contendo os bytes lidos e nulo ou um possvel erro. Analogamente a funo WriteFile ( ) escreve um byte [ ] em um arquivo. package main import ( fmt io/ioutil
CURSO GRATUITO
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( )) } } 2) Buffered Read: Em vez de usar ReadString( ), no caso mais geral de um arquivo no dividido em linhas ou um arquivo binrio, poderamos ter usado o mtodo Read( ) no bufio.Reader, com o parmetro 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 so separadas por um espao, voc pode usar a srie FScan funo do pacote "fmt". Isto aplicado o seguinte programa, que l dados a partir de 3 colunas para as variveis v1, v2 e v3, pois eles so, ento, anexada ao slices coluna.
package main import ( 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) } / * Sada: [ABC FUNC GO] [40 56 45]
CURSO GRATUITO
[150 280 356] */ Observao: O caminho de arquivo subpackage do caminho do pacote fornece funes para a manipulao 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 A compressa pacote da biblioteca padro 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 main import ( 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, Cant 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
CURSO GRATUITO
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++ { outputWriter.WriteString(outputString) } outputWriter.Flush( ) } Alm de um identificador de arquivo, precisamos agora de um bufio Writerfrom. Abrimos um output.dat arquivo para write-only; o arquivo criado quando ele no existe com: outputFile, outputError := os.OpenFile(output.dat, os.O_WRONLY|os.O_CREATE, 0777) Vemos que a funo 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 permisses de arquivo para usar. Os seguintes sinalizadores so comumente usados: os.O_RDONLY: a flag de leitura para acesso somente leitura os.WRONLY: A flag de gravao para acesso somente para gravao os.O_CREATE: a criao da flag: criar o arquivo se ele no existir os.O_TRUNC: a flag truncate: truncar o tamanho 0 se o arquivo j existe Ao ler, as permisses de arquivo so ignoradas para que possamos utilizar um valor de 0. Ao escrever usamos o padro de permisses de arquivos Unix de 0777. Ento ns fazemos o objeto escritor (buffer) com: outputWriter.WriteString(outputString) O loop for repete 10 vezes por gravao para o buffer: outputWriter.WriteString(outputString) ento escrito completamente para o arquivo com: outputWriter.Flush ( ) Nas tarefas de escrita simples, isto pode ser feito mais eficiente com: fmt.Fprintf(outputFile, Some test data.\n) usando a verso F das funes fmt impresso que pode escrever a qualquer io.Writer, incluindo um arquivo. O programa filewrite.go ilustra uma alternativa para fmt.FPrintf:
package main import 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) tambm 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 possvel desconsiderada com _. No fazer uso de um buffer e escrever imediatamente para o arquivo com: f.WriteString( )
CURSO GRATUITO
Copiando arquivos
Como voc copiar um arquivo para outro arquivo? A maneira mais simples usar cpia do pacote io: package main import ( fmt io os ) func main( ) { 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, ento ainda a defer e assim src.Close ( ) executado. Se isto no seria feito, o arquivo de origem permaneceria aberta, usando recursos.
Ns combinamos as tcnicas de leitura em buffer de um arquivo e de linha de comando flag (flag) anlise no exemplo a seguir. Se no h argumentos que digitado em mostrado novamente na sada. Os argumentos so tratados como nomes de arquivos e quando os arquivos existem, o seu contedo mostrado: package main import ( io os fmt bufio flag ) func cat(r *bufio.Reader) { for { buf, err := r.ReadBytes(\n) if err == io.EOF { break }
CURSO GRATUITO
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 } cat(bufio.NewReader(f)) } }
Slices fornecer a maneira padro Go para lidar com I / O buffers, eles so usados na seguinte segunda verso do gato funo, que l um arquivo em um infinito loop for (at EOF fim -de-arquivo) em um buffer em slices, e escreve para a sada padro. 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 cdigo obtido abaixo que utiliza os.file e seu mtodo de leitura do pacote de smio:
package main import ( flag fmt os ) func cat(f *os.File) { const NBUF = 512 var buf [NBUF]byte
CURSO GRATUITO
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( )) } } } } 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: cant open %s: %s\n, flag.Arg(i), err) os.Exit(1) } cat(f) f.Close( ) } }
A palavra-chave muito til para garantir que o arquivo aberto tambm ser fechado no estreitol da funo, 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 }
Esse programa uma boa ilustrao do conceito de interfaces em io. package main import ( bufio fmt os ) func main( ) { / / unbuffered: os.Stdout implements io.Writer
CURSO GRATUITO
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( ) } Sada: hello world! - unbuffered hello world! - buffered Aqui a assinatura real de fmt.Fprintf ( ): func Fprintf(w io.Writer, format string, a ...) (n int, err error) Ele no escreve para um arquivo, ele escreve para uma varivel 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 seqncia de formato para seu primeiro argumento, que deve implementar io.Writer. Fprintf( ) pode escrever a qualquer tipo que tem um mtodo de gravao, incluindo os.Stdout, os arquivos (como os.File), tubos, conexes de rede, canais, etc .., e tambm para escrever buffers de pacote bufio. Este pacote define um tipo escritor struct {} bufio.Writer implementa o mtodo de gravao: func (b *Writer) Write(p [ ]byte) (nn int, err error) Ele tambm tem uma fbrica: dar-lhe um io.Writer, ele retornar um io.Writer tampo na forma de um bufio. Escritor: func NewWriter (wr io.Writer) (b * Writer) Buffer funciona para qualquer coisa que escreve. Nunca se esquea de usar Flush ( ) quando terminar a escrita em buffer, ento o ltimo ouput (saida) no ser escrito.
GO no tem um mecanismo de exception, como o try/catch em Java ou NET, por exemplo:. Voc no pode lanarexception. 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 lanamento de excees ( exception) em camadas inferiores para as camadas mais elevadas de cdigo, poi, usa muitos recursos. O mecanismo que inventado para Go um pode "pegar" exceo (exception) , mas muito mais leve, e mesmo assim s deve ser utilizado como ltimo recurso. A maneira de lidar com erros Go para funes e mtodos para retornar um objeto de erro como sua nica ou o ltimo de valor ou resultado nulo se ocorreu e nenhum erro para chamar funes 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 funo em que ocorreu o erro com uma mensagem de erro para o usurio: dessa forma, se algo der errado, o programa Ir continuar a funcionar e o usurio ser notificado. O objetivo do panic e recover lidar com (inesperados) problemas genuinamente excepcionais e no com erros normais. Rotinas de biblioteca deve muitas vezes retornar algum tipo de indicao de erro para a funo de chamada. A maneira idiomtica de Go para detectar e relatar erro -condies: - Uma funo que pode resultar em um erro retorna duas variveis, um valor e um cdigo de erro; este ltimo nulo, em caso de sucesso, e != nil, no caso de uma condio de erro. - Aps a chamada de funo que o erro seja verificado, no caso de um erro (se o erro != nil) A execuo da funo real (ou se necessrio, o programa inteiro) estar parado. No seguinte cdigo de pacote pack1 testado em seu cdigo de retorno: if value, err := pack1.Func1(param1); err != nil { fmt.Printf(Error %s in pack1.Func1 with parameter %v, err.Error( ), param1)
CURSO GRATUITO
return / / Ou: retorno err } / / Processo (valor) Sempre um erro atribuir a uma varivel dentro de um composto instruo if, tornando o cdigo mais claro. Em vez de fmt.Printf correspondente mtodos do pacote de registro poderiam ser usado, ou mesmo panic, se no se importa que o programa pare. 13.1 Erro de manipulao Go tem um tipo de interface de erro pr-definido: Interface tipo de erro { Erro ( ) string } valores de erros so usados para indicar um estado anormal, mais tarde vamos ver como us -lo em operaes. Os erros de pacote contm um errorString struct que implementa a interface de erro. Para parar a execuo 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 funo 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 main import ( errors fmt ) fmt.Printf(error: %v, errNotFound) } / / error: Not found error
Aplicado numa funo de teste ao parmetro de uma funo 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) } / / Implementao de Sqrt } Voc poderia chamar esta funo da seguinte forma: if f, err := Sqrt(-1); err != nil { fmt.Printf(Error: %s\n, err) } e porque fmt.Printf automaticamente usa seu mtodo String( ), o error-string Error:math - square root of negative number impresso. Porque h muitas vezes ns usamos um prefixo como erro: aqui, no comece sua seqncia de erro com uma letra maiscula. Na maioria dos casos, interessante fazer um tipo struct de erro personalizada, que para alm do (nvel baixo) erro de mensagem tambm contm outras informaes teis, tais como a operao que estava ocorrendo (arquivo aberto, ...), o pleno mtodo do caminho -nome ou url que estava envolvido, etc A String( ), em seguida, fornece uma concatenao informativo de todas essas informaes. Como exemplo,
CURSO GRATUITO
veja PathError que pode ser emitido a partir de uma os.Open: / / PathError registra um erro e o caminho operao e o arquivo que causou. type PathError struct { / / "Aberto", "unlink", etc Path 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-condies de erro possveis 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 remdio ou uma recuperao do erro de situao: // err != nil if e, ok := err.(*os.PathError); ok { / / Situao remdio } 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 funo json.Decode retorna quando ele encontra um erro de sintaxe analisar um documento JSON: type SyntaxError struct { msg string / / descrio 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 cdigo 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 tambm pode definir o seu prprio erro especfico com mtodos adicionais, como net.Error: package net type Error interface { Timeout( ) bool / / o erro de um tempo limite? Temporary( ) bool / / o erro temporrio? }
CURSO GRATUITO
Como voc viu, em todos os exemplos a seguinte conveno de nomenclatura foi aplicado: tipos de erro terminam em "Error" e as variveis de erro so chamados (ou comear) err ou "Err". syscall o de baixo nvel, pacote externo, o que fornece uma interface primitiva para chamadas do sistema operacional subjacente, estes inteiros retornam cdigos 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 tambm fornece um conjunto padro de erro -variveis como os.EINVAL, que vm de syscall - Erros: var ( EPERM ENOENT ESRCH EINTR EIO ... ) Error = Errno(syscall.EPERM) Error = Errno(syscall.ENOENT) Error = Errno(syscall.ESRCH) Error = Errno(syscall.EINTR) Error = Errno(syscall.EIO)
Muitas vezes voc vai querer voltar uma string mais informativo com o valor do parmetro errado inserido por exemplo: isso feito com a funo fmt.Errorf ( ): ele funciona exatamente como fmt.Printf ( ), tendo uma seqncia de formato com um minrio mais especificadores de formato e um nmero correspondente de variveis a serem substitudos. 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 }
Quando os erros de execuo ocorrer, tais como a tentativa de ndice de uma array fora dos limites ou uma assertion tipo de falha, o tempo de execuo Go provoca panic em tempo de execuo com um valor do tipo de interface runtime.Error, eo programa trava com uma mensagem do erro, o valor tem um RuntimeError ( ) mtodo, para distingui-lo de um erro normal. Mas um panic tambm podem ser iniciadas a partir do cdigo diretamente: quando a condio de erro (que estamos testando no cdigo) to grave e Irrecupervel que o programa no pode continuar, a funo
CURSO GRATUITO
de panic usada, o que efetivamente cria um erro de tempo de execuo que vai parar o programa. preciso um argumento de qualquer tipo, geralmente uma string, para ser impresso quando o programa morre. O tempo de execuo Go tem o cuidado de parar o programa e emitir algumas informaes de depurao. Como funciona ilustrado na Listagem package main import fmt func main( ) { fmt.Println(Starting the program) panic(A severe error occurred: stopping the program!) fmt.Println(Ending the program) } E a sada : Starting the program panic: A severe error occurred: stopping the program! panic PC=0x4f3038 runtime.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 usurio conhecido: var user = os.Getenv(USER) func check( ) { if user == { panic(Unknown user: no value for $USER) } } Isto pode ser verificado em uma funo init( ) de um pacote que est importando. Panic tambm pode ser usado no padro 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 funo aninhada, ele imediatamente interrompe a execuo da funo atual, tudo defer declaraes so garantidos para executar e, em seguida, o controle dado ao autor da chamada a funo, que recebe esta chamada a entrar em panic. Este boia at o nvel superior, a execuo adia, e no topo da pilha o programa trava e a condio de erro relatado na linha de comando usando o valor dado a entrar em panic: essa sequncia de terminao chamado panicking. A biblioteca padro contm uma srie de funes, cujo nome prefixado com obrigao, como regexp.MustCompile ou template.Must; estas funes de panic( ) ao converter a string que em uma expresso regular ou modelo produz um erro. Claro derrubar um programa com o panic no deve ser deixado no annimato, por isso todos os esforos devem ser exercidos para remediar a situao e deixar que o programa continue.
CURSO GRATUITO
Recover
Como o nome indica esta funo built -in pode ser usado para recuperar de um panic ou uma condio de erro, que permite que um programa para recupere o controle de um goroutine em panic, parar a sequncia de terminao e, portanto, de continuar a execuo normal. recover s til quando chamado dentro de uma funo diferido: Em seguida, recupera o valor de erro, passou pela chamada de panic, quando usado em execuo normal de uma chamada para recuperar retornar nulo e no tm outro efeito. Resumido: panic faz com que a pilha relaxe at que um adiada recover( ) encontrado ou o programa termina. A funo de proteo no exemplo abaixo invoca o argumento da funo g e protege chamadas de panics de tempo de execuo levantadas por g, mostrando a mensagem x do panic: 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() / /possvel de tempo de execuo de erros } anlogo ao bloco catch no Java e. NET. Log implementa um pacote de registro simples: a logger padro escreve para o erro padro e imprime a data e hora de cada mensagem registrada. Alm das funes println e Printf, as funes slices Exit(1) para depois de escrever a mensagem de log, as funes de sada de forma idntica. As funes de panic chamam panic depois de escrever a mensagem de log, use isso quando uma condio crtica ocorre eo programa deve ser interrompido, como no caso em que um servidor web no poderia ser iniciado. O pacote de log tambm define um tipo de interface Logger com os mesmos mtodos, 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 main import ( 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); }
CURSO GRATUITO
/ * Sada: Calling test Panicking bad end Test completed */ Defer, panic e recover formam em um sentido tambm um mecanismo de controle de fluxo, como if, for, etc Esse mecanismo usado em vrios lugares na biblioteca padro Go, por exemplo, no pacote json ao decodificar ou no pacote regexp na funo Compile. A conveno 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 explcitas.
Esta uma prtica que cada escritor de pacotes personalizados devem ser aplicadas: 1) sempre recuperar de panic no pacote: sem o explcito panic( ) devem ser autorizados a cruzar um limite de pacote 2) 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 funes no-exportados, pode ser til (e melhorar a legibilidade) para usar o panic para indicar condies de erro que devem ser traduzidos em um erro para a funo de chamada. Isto muito bem ilustrado no cdigo a seguir. Temos um pacote de anlise simples que analisa cadeias de entrada de slices de inteiros, mas tambm contm o seu ParseError especializado. Este panic pacote (em fields2numbers funo) quando no h nada para converter ou quando a converso para nmero inteiro falhar. No entanto, a funo Parse exportado pode recuperar desta e retorna um erro com todas as informaes para o seu chamador. Para mostrar como funciona o pacote chamado de panic_recover. package parse import ( fmt strings strconv ) / / A ParseError indica um erro na converso de uma palavra em um nmero inteiro. type ParseError struct { Index int / / O ndice para a lista separada por espaos de palavras. Word string / / A palavra que gerou o erro de anlise. / / um erro em bruto que precipitou a este erro. Error err } / / String retorna uma mensagem de erro legvel. func (e *ParseError) String( ) string { return fmt.Sprintf(pkg parse: error parsing %q as int, e.Word) } / / Parse analisa as palavras separadas por espao 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
CURSO GRATUITO
} 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 } Outro exemplo:
package main import ( 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 Mtodo String( ) a partir de ParseError usado fmt.Println (err) continuar } fmt.Println (nums) } } / * Sada: [1 2 3 4 5] Parsing 100 50 25 12.5 6.25: pkg parse: error parsing 12.5 as int Parsing 2 + 2 = 4: pkg parse: error parsing + as int Parsing 1st class: pkg parse: error parsing 1st as int Parsing : pkg: no words to parse */
Cada vez que uma funo retorna devemos testar se resultou em um erro: esta pode levar a um cdigo repetitivo e tedioso. Combinando o mecanismo de defer/panic/recover com closures podem resultar
CURSO GRATUITO
em um esquema muito mais elegante que agora vamos discutir. No entanto, aplicvel apenas quando todas as funes tm a mesma assinatura, que bastante restritiva. Um bom exemplo de seu uso em aplicaes web, onde todas as funes de manipulador so do seguinte tipo: func handler1(w http.ResponseWriter, r *http.Request) { ... } Suponha que todas as funes tm a assinatura: func f(a type1, b type2) O nmero de parmetros e seus tipos Irrelevante. Damos este tipo um nome: fType1 = func f(a type1, b type2) Nosso esquema utiliza duas funes auxiliares:
i) check: uma funo que testa se um erro ocorreu, e panics se assim for: func check(err error) { if err != nil { panic(err) } } ii) esta uma funo wrapper. preciso uma funo fn do nosso tipo fType1 e retorna essa funo 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; alm de simplesmente imprimir o aplicativo tambm pode produzir uma sada personalizada para o usurio usando o pacote de modelo . A funo de verificao (check( ) usado em cada funo chamada, como esta: func f1(a type1, b type2) { ... f, _, err := / / chamada de funo / mtodo check(err) t, err := / / chamada de funo / mtodo check(err) _, err2 := / / chamada de funo / mtodo check(err2) ... } O main( ) ou outra funo chamada deve ento chamar as funes necessrias envolta em errorHandler, como este: func main( ) { errorHandler(f1) errorHandler(f2) ... } Usando este mecanismo todos os erros sero recuperados e o cdigo de verificao de erros depois de uma chamada de funo reduzido para check(err). Neste esquema manipuladores de erro diferentes tm de ser utilizados para os diferentes tipos de funes, eles podem ser escondidos dentro de uma manipulao de erro pacote. Alternativamente uma abordagem mais geral poderia estar usando uma slice de interface vazia como parmetro e tipo de retorno.
CURSO GRATUITO
Iniciando um comando ou programa externo
O pacote contm o sistema operacional StartProcess funo a ser chamada ou iniciar comandos OS externos ou executveis binrios, seu primeiro argumento o processo a ser executado, o segundo pode ser usado para passar algumas opes ou argumentos, ea terceira uma estrutura que contm informaes bsicas 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 contm as estruturas e funes para realizar a mesma tarefa com mais facilidade; mais importantes so exec.Command(name string, arg ...string) e Run ( ). O primeiro tem o nome de um comando OS ou executvel e cria um objeto de comando, que pode ento ser executado com Run ( ) que usa esse objeto como seu receptor. O programa seguinte (que s funciona no Linux porque os comandos do Linux so executados) ilustra a sua utilizao: package main import ( 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) / * Sada: 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)
CURSO GRATUITO
} 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)
Goroutines e Canais
Como esperado de uma linguagem de programao do sculo 21, Go vem com suporte embutido para comunicao entre aplicaes (networking, cliente -servidor, computao distribuda) e suporte para aplicativos simultneos. Estes so os programas que executam diferentes partes do cdigo ao mesmo tempo, possivelmente em diferentes processadores ou computadores. Os blocos de construo bsicos Go prope para a estruturao de programas concorrentes so goroutines e canais. A sua aplicao exige o apoio da linguagem, o compilador e tempo de execuo. A coleta de lixo que Go oferece tambm essencial para a programao concorrente fcil. No se comunique atravs da partilha de memria. Em vez disso, compartilhar a memria por meio da comunicao. Um aplicativo um processo em execuo em uma mquina, um processo uma entidade de executar de forma independente que executado em seu prprio espao de endereo na memria. Um processo composto de um ou mais segmentos do sistema operacional que esto sendo executadas simultaneamente entidades que compartilham o mesmo espao de endereo. Quase todos os programas reais so de vrios segmentos, de modo a no introduzir o tempo de espera para o usurio 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 execuo de cdigo em paralelo em diferentes conjuntos de dados). Tal aplicao simultnea pode executar em um processador ou ncleo usando um nmero de threads, mas apenas quando o mesmo processo de aplicao executada no mesmo ponto no tempo em um nmero de ncleos ou processadores que verdadeiroamente chamado paralelizado. O paralelismo a capacidade de fazer as coisas funcionarem rapidamente usando mltiplos processadores. Deste modo, programas simultneos podem ou no ser paralelas. Aplicativos multithreaded so notoriamente difceis de acertar, o principal problema que os dados compartilhados na memria, que podem ser manipuladas pelos diferentes segmentos de uma forma no previsvel, proporcionando assim resultados, por vezes, Irreproduzveis e aleatrios (chamados de condies de corrida). ! No use variveis globais ou de memria compartilhada, eles fazem o seu cdigo no seguro para executar simultaneamente! A soluo est em sincronizar os diferentes tpicos, e trancar os dados, de modo que apenas um thread por vez pode alterar os dados. Go tem instalaes para o bloqueio em sua biblioteca padro na sincronia pacote para quando eles so necessrios no cdigo de nvel inferior.Mas a experincia passada em engenharia de software mostrou que isso leva ao complexo, sujeito a erros de programao e desempenho diminuindo, por isso esta abordagem clssica no claramente o caminho a percorrer para multicore moderno e multiprocessador de programao: o "thread -per-connection'- modelo no quase eficiente o suficiente. Vai aderir a outro, em muitos casos paradigmticos mais adequado, que conhecido como comunicao de processos seqenciais (CSP, inventado por C. Hoare) ou tambm chamados a mensagem de passagem de modelo (como aplicado em outras lnguas, como Erlang). As partes de um aplicativo que executar simultaneamente so chamados goroutines em Go, que esto em virr em execuo simultaneamente clculos. No h correspondncia 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
CURSO GRATUITO
Go tempo de execuo. Goroutines executado no mesmo espao de endereo, de modo que o acesso memria compartilhada deve ser sincronizada, o que poderia ser feito atravs do pacote de sincronizao, 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 criao e gerenciamento de threads. Goroutines so leves, muito mais leve do que um fio. Eles tm uma pegada muito pequena (use pouca memria e recursos): eles so criados com uma memria stack-4K espao na pilha. Porque eles so baratos para criar, um grande nmero deles pode ser iniciado na mosca, se necessrio (na ordem de 100 milhares de pessoas no mesmo espao de endereamento). Alm disso, eles usam uma pilha segmentado para o cultivo de forma dinmica (ou encolhendo) sua memria -uso; empilhar gesto automtico. As pilhas no so gerenciados pelo coletor de lixo, ao invs disso eles so liberados diretamente quando as sadas goroutine. Goroutines pode ser executado atravs de mltiplas threads do sistema operacional, mas crucialmente, eles tambm podem ser executados dentro de threads, permitindo -lhe lidar com mGoade de tarefas com um consumo de memria relativamente pequena. Goroutines time-slice em tpicos SO por assim dizer, de modo que voc pode ter qualquer nmero de goroutines sendo atendidos por um nmero menor de fios do sistema operacional, eo tempo de execuo Go inteligente o suficiente para perceber qual desses goroutines est bloqueando alguma coisa e sair e fazer outra coisa. Dois estilos de concorrncia existe: determinista (ordenao bem definida) e no -determinstico (bloqueio / excluso mtua mas a ordem no definida). Goroutines e canais da Go promover concorrncia determinista (por exemplo, os canais com um remetente, um receptor), que mais fcil de se trabalhar. A goroutine implementado como uma funo ou mtodo (isso tambm pode ser uma funo annima ou lambda) e chamado (invocado) com a palavra -chave movimento. Isso inicia a funo de execuo em paralelo com a computao actual, mas, no mesmo espao de endereos e com a sua prpria pilha. A pilha de um goroutine cresce e encolhe, conforme necessrio, no h possibilidade de estouro de pilha, o programador no precisa se preocupar com o tamanho da pilha. Quando o goroutine termina ele sai em silncio: nada retornado para a funo que comeou. A funo main ( ) que todos os programas de Go deve ter tambm pode ser visto como um goroutine, embora no seja iniciado com movimento. Goroutines pode ser executado durante a inicializao do programa (no init ( )funo). Quando um goroutine , por exemplo, muito muito do processador voc pode chamar runtime.Gosched ( ) periodicamente em laos seu clculo: isto produz o processador, permitindo que outros goroutines para executar, mas no suspende a goroutine atual, portanto, a execuo reinicia automaticamente. Usando Gosched ( ) os clculos so mais uniformemente distribudos e comunicao no fome.
Primitivas de concorrncia da Go fornecer a base para um bom desenho do programa de concorrncia: expressar a estrutura do programa, de modo a representar as aes que executam de forma independente, por isso a nfase de Go no est no 1 lugar em paralelismo: programas concorrentes podem ou no podem ser paralelas. O paralelismo a capacidade de fazer as coisas funcionarem rapidamente usando mltiplos processadores. Mas acontece que na maioria das vezes que um programa concorrente bem desenhado tambm tem excelentes capacidades paralelas desempenho. Na atual implementao do tempo de execuo (Jan 2012) Go no paralelizar cdigo por padro, apenas um nico ncleo ou processador dedicado a um programa de Go, independentemente de quantos goroutines so iniciados nele, assim que estes goroutines esto funcionando em simultneo, eles no esto sendo executados em paralelo: apenas um goroutine est em execuo ao mesmo tempo. Isso provavelmente vai mudar, mas at l, a fim de deixar o seu programa executar simultaneamente por mais ncleos, ou seja, para que goroutines esto realmente funcionando em paralelo, voc tem que usar as GOMAXPROCS variveis. Isto indica o tempo de execuo quantos goroutines deve executar simultaneamente. Tambm s os gc-compiladores tm uma verdadeiroa implementao de goroutines, mapeando -os em tpicos OS conforme o caso. Com o compilador gccgo, um fio OS ser criado para cada goroutine.
CURSO GRATUITO
Usando GOMAXPROCS
De acordo com os compiladores de gc (6g ou 8G) voc deve definir GOMAXPROCS a mais do que o valor padro 1 para permitir que o suporte de tempo de execuo 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 nmero de goroutines execuo. Suponhamos que n o nmero de ncleos de transformadores ou na mquina. Se voc definir o ambiente GOMAXPROCS varivel> = n, ou ligue runtime.GOMAXPROCS (n), ento os goroutines so divididos (distribudo) entre os n processadores. Mais processadores no entanto, no significa necessariamente uma melhora linear no desempenho, principalmente porque necessrio mais comunicao: os de transmisso de mensagens gerais aumenta. Uma regra de ouro experiencial parece ser que para n ncleos definio GOMAXPROCS a n-1 produz o melhor desempenho, e tambm o seguinte devem ser seguidas: nmero de goroutines> 1 + GOMAXPROCS> 1 Portanto, se houver apenas um goroutine execuo em um determinado ponto no tempo, no deestreito GOMAXPROCS! Aqui esto algumas outras observaes de experimentos: em uma performance laptop 1 CPU melhorou quando GOMAXPROCS foi aumentado para 9. Em uma mquina de ncleo 32, o melhor desempenho foi alcanado com GOMAXPROCS = 8, um nmero maior no aumentou desempenho nesse benchmark. Valores muito grandes de GOMAXPROCS degradado desempenho apenas ligeiramente, usando a opo "H" para "top" mostrou apenas 7 tpicos ativos, por GOMAXPROCS = 100. Programas que realizam computao concorrente dever beneficiar de um aumento no GOMAXPROCS; ver goroutine_select2.go Resumido: GOMAXPROCS igual ao nmero de concorrentes ( ) tpicos, em uma mquina com mais de um ncleo, como muitos segmentos como existem ncleos podem executar em paralelo.
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 necessrio.
package main import ( fmt time ) func main( ) { fmt.Println(In main( )) go longWait( ) go shortWait( ) fmt.Println(About to sleep in main( )) / / Sleep trabalha com um Perodo em nanossegundos (ns)! time.Sleep(10 * 1e9) fmt.Println(At the end of main( )) }
CURSO GRATUITO
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( ) Beginning shortWait( ) End of shortWait( ) End of longWait( ) At the end of main( ) / / depois 10s
As trs funes main ( ), longWait ( ) e shortWait ( ) so iniciados nesta ordem, como unidades de processamento independentes, e em seguida, trabalhar em paralelo. Cada funo gera uma mensagem no seu incio e no estreitol do seu processamento. Para simular os seus tempos de processamento, usamos a funo do sono do pacote de tempo. Sleep ( ) interrompe o processamento da funo ou goroutine para a quantidade indicada de tempo, o que dado em nanossegundos (ns, o 1e9 notao representa 1 vezes 10 elevado potncia 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 aps as duas goroutines. Se no (se deixarmos main ( ) parar por apenas 4s), main ( ) interrompe a execuo mais cedo e longWait ( ) no ter a chance de ser concludo. Se no esperar em main ( ), o programa pra e as goroutines morrer com ele. Quando a funo main ( ) retorna, o programa encerrado: no esperar por outro (no principal) goroutines para ser concludo. Essa a razo por que, em programas de servidor, onde cada pedido tratado por uma resposta comeou como um goroutine, a funo do servidor ( ) devem ser mantidos vivos. Isso geralmente feito por inici-lo como um loop infinito. Alm disso goroutines so unidades independentes de execuo e, quando um certo nmero deles comea um aps o outro no pode depender de quando um goroutine Ir realmente ser iniciado. A lgica do seu cdigo deve ser independente da ordem em que goroutines so invocados. Para contrastar isso com um nico segmento, execuo sucessiva, remova o go palavras -chave, e deixar que o programa seja executado novamente. Agora, a sada : 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 disposio muito grande. Dividir a array em uma srie de cortes que no se sobrepem, e iniciar um goroutine em cada slice com o algoritmo de busca. Desta forma, um nmero de segmentos paralelos podem ser utilizadas para a busca para a tarefa, e o tempo de pesquisa global, certamente, ser diminuda (dividido pelo nmero de goroutines).
CURSO GRATUITO
Em nossos primeiros exemplos os goroutines executado de forma independente, eles no se comunicam. Claro que para ser mais til, eles tm de se comunicar: envio e recebimento de informaes entre eles e coordenar / sincronizar os seus esforos. Goroutines poderia se comunicar usando variveis compartilhadas, mas isso altamente desencorajada, porque esta forma de trabalho apresenta todas as dificuldades com memria compartilhada em multi -threading. Em vez Go possui um tipo especial, o canal, que como um condute (tubo ou pipe) atravs do qual voc pode enviar os valores digitados e que cuida da comunicao entre goroutines, evitando todas as armadilhas da memria compartilhada, o prprio ato de comunicao por meio de um garantias sincronizao de canal. Os dados so passados em torno de canais: apenas um goroutine tem acesso a um item de dados em um determinado momento: ento corridas de dados no 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 fbrica. Uma mquina (o goroutine produtor) coloca itens para o cinto, e uma mquina (o consumidor goroutine) leva -los para a embalagem. Canais servem o duplo objectivo de comunicao em troca de um valor -com que dois clculos (goroutines) esto em um estado conhecido em qualquer momento garantir a sincronizao. A declarao de um canal o formato geral: var identifier chan datatype O valor do canal no 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, tambm da interface vazio { }. at mesmo possvel (e por vezes til) para criar um canal de canais. Um canal , de fato, uma fila de mensagens digitada: os dados podem ser transmitidos atravs dele. uma estrutura de First In First Out (FIFO) e, assim, preservar a ordem dos itens que so enviados para eles (para aqueles que esto familiarizados com ele, um canal pode ser comparado a um tubo de duas vias em conchas Unix). Um canal tambm um tipo de referncia, por isso temos de usar a marca ( ) para alocar memria para ele. Aqui est uma declarao de um canal ch1 de strings, seguido de sua criao (instanciao): var ch1 chan string ch1 = make(chan string) Mas claro que isso pode ser reduzido para: ch1 := make(chan string) E aqui ns construmos um canal de canais de int: chanOfChans := make(chan chan int) ou use funcChan := chan func( ) Assim, os canais so objetos de primeira classe: eles podem ser armazenados em variveis, passados como argumentos para funes, retornados de funes e enviou -se atravs de canais. Alm disso, eles so digitados, permitindo que o sistema de tipo para pegar erros de programao como tentar enviar um ponteiro sobre um canal de inteiros.
Este operador representa muito intuitivamente a transmisso de dados: a informao flui na direo da seta. Para um canal (envio): ch <- int1 significa: int1 varivel enviado atravs do canal ch (operador binrio, infixo = send) A partir de um canal (recepo), 3 formas: int2 = <- ch significa: int2 varivel recebe dados (recebe um novo valor) a partir do ch canal (unrio operador de prefixo, prefixo = receber), o que supe int2 j est declarada, se no ele pode ser escrita como: int2: = <- ch
CURSO GRATUITO
<- Ch pode em si mesmo ser usado para tirar o (prximo) o valor a partir do canal, este valor eficazmente eliminada, mas podem ser testadas em cima, de modo que o cdigo seguinte legal: if <-ch != 1000 { ... } O mesmo operador <- usado para enviar e receber, mas Go descobre dependendo dos operandos o que fazer. Apesar de no ser necessrio, para facilitar a leitura do nome do canal geralmente comea com ch ou contm 'chan'. O canal de enviar e receber operaes so atmicas: eles sempre completa sem interruption.The uso do operador de comunicao ilustrado no exemplo package main import ( fmt 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) } } Sada: Washington Trpoli 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 parmetro para fazer isso. Experimente o que acontece quando voc comentar time.sleep (1e9). Aqui vemos que a sincronizao entre os goroutines torna-se importante: main( ) espera por um segundo, de modo que ambos os goroutines pode chegar a concluso, se isso no permitido sendData ( ) no tm a oportunidade de produzir sua sada. 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 no funciona mais, o tempo de execuo Go lana panic: ---- Error run E:/Go/GoBoek/code examples/chapter 14/goroutine2.exe code Crashed ---- Program exited with code -2147483645: ---- Programa saiu com o cdigo -2147483645: adormecido-impasse! Com panic: todos so goroutines
CURSO GRATUITO
Por que isso ocorre? O tempo de execuo capaz de detectar que todos os goroutines (ou apenas um, talvez, neste caso) esto 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 no pode prosseguir. Esta uma forma de impasse, eo tempo de execuo capaz de detect-lo para ns. Observao: No use instrues de impresso para indicar a ordem de enviar para e receber a partir de um canal: este poderia ser fora de ordem com o que realmente acontece devido ao lapso de tempo entre a declarao de impresso e do canal real de envio e recebimento.
Bloqueio de canais
Por padro, a comunicao sncrona e sem buffer: Envia no completar at que haja um receptor para aceitar o valor. Pode-se pensar em um canal sem buffer como se no h espao 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 operaes bloquear at que o outro lado est pronto: 1) A operao de envio de um canal (e o goroutine ou funo em que se encontra) blocos at que um receptor est disponvel para o mesmo canal: se no h nenhum destinatrio para o valor em ch, nenhum outro valor pode ser colocado no canal: no novo valor pode ser enviado no ch quando o canal no est vazio. Assim, a operao de envio vai esperar at ch torna -se disponvel novamente: este o caso quando o valor de canal recebido (pode ser colocado em uma varivel). 2) A operao de recebimento por blocos de canal (eo goroutine ou funo em que se encontra), at que o remetente est disponvel para o mesmo canal: se no h valor no canal, os blocos do receptor. Embora isto parea uma restrio severa, ele funciona bem na maioria das situaes prticas. Isto ilustrado na channel_block.go programa, em que a bomba goroutine envia inteiros num ciclo infinito no canal. Mas, porque no h nenhum receptor, a nica sada o nmero 0. package main import fmt func main( ) { ch1 := make(chan int) go pump(ch1) fmt.Println(<-ch1) } func pump(ch chan int) { for i:= 0; ; i++ { ch <- i } } Sada: 0 A funo da bomba ( ) que fornece os valores para o canal, por vezes chamado um gerador. Para desbloquear o canal de definir uma funo que l suck do canal em um loop infinito, consulte a : func suck(ch chan int) { for { fmt.Println(<-ch) } } e comear a isso como um goroutine em main ( ): go pump(ch1) go suck(ch1)
CURSO GRATUITO
time.Sleep(1e9) D a 1s do programa a ser executado: agora dezenas de milhares de nmeros inteiros aparecem na sada.
A comunicao , por conseguinte, uma forma de sincronizao: dois goroutines a troca de dados atravs de um canal de sincronizao, no momento de comunicao (a rendez-vous de goroutines). Canais sem buffer tornar uma ferramenta perfeita para sincronizar mltiplas goroutines. ainda possvel que os dois lados bloquear uns aos outros, criando o que chamado de uma situao de impasse. O tempo de execuo Go Ir detectar isto e entrar em panic, parar o programa. Um impasse quase sempre causada por m concepo do programa. Vemos que as operaes de canal em canais sem buffer pode bloquear. A maneira de evitar isso a concepo do programa de tal forma que o bloqueio no ocorrer, ou usando canais de buffer. package main import ( fmt ) func f1(in chan int) { fmt.Println(<-in) } func main( ) { out := make(chan int) out <- 2 go f1(out) } canais de tomada assncronos um canal com uma memria intermdia Um canal sem buffer pode conter apenas um item e por essa razo, por vezes, demasiado restritiva. Podemos prever um tampo no canal, cuja capacidade de se definir em um comando estendido marca, como esta: buf := 100 ch1 := make(chan string, buf) buf o nmero de elementos (aqui strings) do canal pode conter. Enviar para um canal tamponada no bloquear a menos que o buffer esteja cheio (a capacidade de utilizar completamente), e a leitura de um canal tamponada no bloquear a menos que o buffer esteja vazio. A capacidade tampo no pertencem ao tipo, por isso, possvel (embora talvez perirsos) para atribuir canais com diferentes capacidades para o outro, desde que eles tm o mesmo tipo de elemento. A funo cap embutido em um canal retorna essa capacidade de buffer. Se a capacidade for maior que 0, o canal assncrona: operaes de comunicao ter sucesso sem bloquear se o buffer no est cheio (envia) ou no vazia (recebe), e os elementos so recebidos na ordem em que so enviados. Se a capacidade zero ou ausente, a comunicao bem -sucedida somente quando tanto um emissor e receptor esto prontas. Para sintetizar: ch := make(chan type, value) valor == 0 sncrona, sem buffer (Bloqueio)
CURSO GRATUITO
valor> 0 assncrona, tamponada (sem bloqueio) at elementos de valor Se voc usar buffers nos canais, o programa Ir reagir melhor aos aumentos repentinos de nmero de "pedidos": ele vai reagir mais elstica, ou com o termo oficial: vai ser mais escalvel. Mas projetar seu algoritmo, em primeiro lugar com canais sem buffer, e s introduzir o buffer quando o primeiro problemtico.
A fim de saber quando feito um clculo, passe um canal no qual ele pode informar. No nosso exemplo de go sum(bigArray), isso seria o mesmo que: ch := make(chan int) go sum(bigArray, ch) / / bigArray coloca a soma calculada em ch / / fazer outra coisa por um tempo sum := <-ch / / espera e recuperar a soma Podemos tambm usar um canal para fins de sincronizao, assim, efetivamente us -lo como o que chamado de um semforo na computao 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 declarao em uma funo 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 padro de semforo, como discutido na seco seguinte.
Semaphore padro
Isso ilustrado no seguinte trecho: a computao goroutine sinaliza a sua concluso, 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 concludo, 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 tambm pode ser outra coisa, no est ligado ao resultado, como nesta funo goroutine lambda: ch := make(chan int) go func( ) { / / doSomething ch <- 1 / / Envia um sinal, valor no importa. }() doSomethingElseForAWhile( ) <-Ch / / Espera goroutine terminar; descartar valor enviado. Ou neste trecho onde esperamos por 2 sort-goroutines, que cada espcie uma parte de uma slice s, a completar:
CURSO GRATUITO
done := make(chan bool) / / DoSort uma funo 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
No seguinte trecho de cdigo, temos um padro full-blown semforo onde N computaes doSomething ( ) sobre uma slice de Float64 de com esse tamanho so 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 clculos 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 terminar for i: = 0; i <N; i + + {<-sem}
Observe a utilizao do fecho: a corrente i, xi so passados para o fecho como parmetros, mascarando as variveis i, xi do exterior for-loop. Isso permite que cada goroutine ter sua prpria cpia do i, xi, caso contrrio, a prxima iterao do atualizaria loop for i, xi em todos goroutines. Por outro lado, a slice res no passado para o fecho, uma vez que cada goroutine no precisa de uma cpia separada dele. A slice res faz parte do ambiente do fechamento, mas no um parmetro. Cada iterao do loop for feito em paralelo: for i, v := range data { go func (i int, v float64) { doSomething(i, v) ... } (i, v) } Computando as iteraes de um loop for em paralelo poderia dar grandes ganhos de desempenho. Mas isso s possvel quando todas as iteraes so completamente independentes uns dos outros. Algumas lnguas, como Fortaleza ou outras estruturas paralelas implementar esta como uma construo separada, em Go estes so facilmente implementados com goroutines:
CURSO GRATUITO
Semforos so um mecanismo muito geral de sincronizao que pode ser usado para implementar semforos (fechaduras exclusivos), limitar o acesso a vrios recursos, resolver o problema dos leitoresescritores, etc No h implementao de semforos no pacote de sincronizao do Go, mas eles podem ser facilmente emulado usando um canal de buffer: a capacidade do canal tamponada o nmero de recursos que deseja sincronizar o comprimento (nmero de elementos actualmente armazenadas) do canal o nmero de recursos actualmente a ser usado a capacidade de menos do comprimento do canal o nmero de recursos livres (o valor inteiro de semforos tradicionais) Ns no nos importamos com o que est armazenado no canal, apenas a sua extenso e, portanto, vamos comear por fazer um canal que tem comprimento varivel, mas 0 tamanho (em bytes): type Empty interface { } type semaphore chan Empty Em seguida, possvel inicializar um semforo com um valor inteiro que codifica o nmero de recursos disponveis N: sem = make(semaphore, N) Agora nossas operaes de semforo so 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 padro de fbrica
Outro padro comum neste estilo de programao o seguinte: em vez de passar um canal como um parmetro para uma goroutine, deixa a funo de fazer o canal e devolv -lo (para que ele desempenha o papel de uma fbrica); dentro da funo uma funo lambda chamado como um goroutine.
CURSO GRATUITO
14,5 channel_idiom.go: package main import ( fmt time ) func main( ) { stream := pump( ) go suck(stream) ) / / As duas linhas acima pode ser abreviado para: go 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) { for { fmt.Println(<-ch) } } Para gama aplicado aos canais
A clusula de gama em loops aceita um ch canal como um operando, caso em que o loops sobre os 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 cdigo a seguir para continuar a executar. Obviamente outro goroutine deve ser escrito para pc (caso contrrio, os blocos de execuo do loop for) e deve fechar ch quando feito por escrito. A funo de sugar pode aplicar isso e tambm lanar esta ao em um goroutine, nosso antir programa torna-se agora: package main import ( 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( ) {
CURSO GRATUITO
for v := range ch { fmt.Println(v) } }( ) } IDIOM: Canal padro Iterator Esse padro utiliza o padro 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 contm um campo de ndice de itens enderevel. Por isso, podemos definir um mtodo que retorna um canal s de leitura de itens: func (c *container) Iter ( ) <-chan items { 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 grfico algoritmos, este simples loop for poderia ser substituda por uma busca em profundidade). O cdigo que chama esse mtodo pode ento interagir sobre o recipiente como: for x := range container.Iter( ) { ... } que pode ser executado em sua prpria goroutine, por isso, em seguida, o iterador acima emprega um canal e dois goroutines (que podem executar em segmentos separados). Ento ns temos um padro de produtor-consumidor tpico. Se o programa terminar antes do goroutine feito escrever valores para o canal, ento isso no ser goroutine lixo coletado, o que prprio do projeto. Este parece ser um comportamento errado, mas os canais so para threadsafe comunicao. Nesse contexto, um goroutine pendurado tentando escrever para um canal que ningum nunca vai ler provavelmente um bug e no algo que voc gostaria de estar em silncio coleta de lixo. Para o padro do Produtor-Consumidor Suponha que temos um Produce function ( ) que fornece os valores necessrios para uma funo 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 cdigo: var send_only chan<- int var recv_only <-chan int / / canal s pode receber dados / / canal s pode enviar dados
CURSO GRATUITO
Receba somente canais (<-chan T) no pode ser fechada, pois o fechamento de um canal pretende ser um caminho para um remetente para sinalizar que h mais valores sero enviados para o canal, por isso no tem nenhum significado para receber somente os canais. Todos os canais so criados bidirecional, mas podemos atribu-los a idirecional variveis de canal, como neste trecho de cdigo: var c = make(chan int) / / bidirecional go source(c) go sink(c) func source(ch chan<- int) { for { ch <- 1 } } func sink(ch <-chan int) { for { <-ch } }
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 sada: 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 notao idirecionalidade temos certeza de que o goroutine no realizar operaes de canais no permitidas. Aqui est um excelente exemplo concreto e mais retiradas do Go Tutorial que imprime os nmeros primos na sua sada, o uso de filtros ("peneiras") como seu algoritmo. package main import fmt / / Envia a seqncia 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 divisveis por prime. func filter(in, out chan int, prime int) { for { i := <-in / / Recebe valor da nova varivel 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.
CURSO GRATUITO
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, sada chan int, int) nobre cpias inteiros para o canal de sada de descartar qualquer coisa divisvel por prime. Assim, para cada primo um novo goroutine lanado, trabalhando em conjunto no processo: o gerador e filtros executar concorrentemente. Sada: 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 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 1009 1013....... Na segunda verso do idioma descrito acima aplicado: as funes peneira, gerar e filtro so fbricas, eles fazem um canal e devolv-lo, e eles usam funes lambda como goroutines. A rotina principal agora muito curta e clara: ela chama sieve( ), que retorna um canal contendo os nmeros primos, e, em seguida, o canal impresso via fmt.Println (< -primes). Verso 2: package main import fmt / / Envia a seqncia 2, 3, 4, para retorno do canal func generate( ) chan int { ch := make(chan int) go func( ) { for i := 2; ; i++ { ch <- i } }( ) return ch } / / Filtrar valores de entrada divisveis por primo, envie um descanso para o canal voltou func 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)
CURSO GRATUITO
go func( ) { ch := generate( ) for { prime := <-ch ch = filter(ch, prime) out <- prime } }( ) return out } func main( ) { primes := sieve( ) for { fmt.Println(<-primes) } } Sincronizao de goroutines: fechar um canal de testes para os canais bloqueados
Os canais podem ser fechados explicitamente, no entanto eles no so como arquivos: voc no costuma precisar fech-las. Encerramento de um canal s necessria quando o receptor deve ser dito que no h mais valores prximos. 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 funo close (ch): esta marca o canal como incapaz de aceitar mais valores por meio de uma operao de envio <-; envio ou fechar um canal fechado provoca panic em tempo de execuo. uma boa prtica de fazer isso com uma declarao de adiamento imediatamente aps a tomada do canal (Quando apropriado em uma dada situao): ch: = make (chan float64) defer perto (ch) defer close(ch) O segundo feito com a vrgula, ok operador: este testa se o canal fechado e, em seguida, retorna true, caso contrrio false. Como podemos testar que podemos receber sem bloquear (ou que ch canal no est fechada)? v, ok: = <-chv, ok := <-ch / / ok verdade se v recebeu valor
Muitas vezes isso usado em conjunto com uma instruo 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 := <-ch if !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 sada. Para fazer um canal sem bloqueio de leitura que voc precisa usar select
CURSO GRATUITO
package main import 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) } func getData(ch chan string) { for { input, open := <-ch if !open { break } fmt.Printf(%s , input) } } Aqui est o que alterado no cdigo: - S sendData( ) agora um goroutine, getData( ) executado no mesmo segmento como main( ): go sendData(ch) getData(ch) ) - No fim da funo 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 prtica para ler o canal com uma declarao de alcance, porque este ser automaticamente detectar quando o canal est fechado: for input := range ch { process(input) }
CURSO GRATUITO
O bloqueio eo padro produtor -consumidor: No padro de canal a partir do exercicio de iterao a relao entre os dois goroutines de tal modo que um geralmente um bloquear a outra. Se o programa executado em uma mquina com vrios ncleos, apenas um processador ser empregue na maioria das vezes. Isto pode ser melhorado atravs da utilizao de um canal com um tamanho de buffer maior do que 0.Por exemplo, com um tampo de tamanho 100, a iterao pode produzir pelo menos 100 itens a partir do recipiente antes de bloquear. Se o goroutine consumidor est sendo executado em um processador separado, possvel que nem goroutine nunca Ir bloquear. Como o nmero de itens no recipiente do conhecimento geral, no 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 memria necessria para repetir em qualquer recipiente dado, ento a capacidade do canal deve ser limitado a um nmero mximo. Tempo ou de benchmarking seu cdigo Ir ajud -lo a encontrar a capacidade do buffer para uso de memria mnima e um timo desempenho.
Obtendo os valores de diferentes goroutines executando simultaneamente pode ser realizado com a palavra-chave de seleo, que se assemelha a instruo de controle switch (Captulo 5 5.3) e s vezes chamado de comunicaes switch , ele age como um, voc est pronto mecanismo de votao; selecionar escuta para os dados de entrada nos canais, mas tambm 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 clusula de default opcional; caro atravs de um comportamento, como no switch normal, no permitido. A seleo encerrado quando uma pausa ou retorno executado em um de seus casos. O seleto faz : ele escolhe qual das vrias comunicaes registradas por seus casos, pode prosseguir. se todos so bloqueados, ele espera at que se possa proceder se mltipla pode continuar, ele escolhe um ao acaso. quando nenhuma das operaes do canal pode prosseguir ea clusula padro est presente, ento este executado: o padro sempre executvel (ou seja: pronto para executar). Usando uma operao de envio em uma instruo SELECT com um caso padro garante que o envio ser non-blocking! Se no houver nenhum dos casos, os blocos selecionados execuo para sempre. O select-statement implementa uma espcie de ouvinte-padro, e por isso usado principalmente dentro de um loop (n infinito), quando uma determinada condio atingida, o lao encerrado por uma instruo break. No programa goroutine_select.go h 2 canais CH1 e CH2 e 3 goroutines pump1 ( ), pump2 ( ) e sugar ( ). Este um padro produtor-consumidor tpico. Em loops infinitos CH1 e CH2 so preenchidos com nmeros inteiros atravs pump1 ( ) e pump2 ( ); chupar ( ) as pesquisas para a entrada tambm em um loop sem fim, leva os inteiros dentro de CH1 e CH2 na clusula select, e gera-los. O caso em que escolhido depende de qual a informao do canal recebida. O programa encerrado em principal, depois de 1 segundo. package main import ( fmt time
CURSO GRATUITO
runtime ) func main( ) { runtime.GOMAXPROCS(2) 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++ { 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: Sada: 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 sada produzida em 1 s bastante surpreendente, se considerarmos que (goroutine_select2.go) obtemos cerca de 90 mil nmeros.
/ / in goroutine_select2.go
O pacote de tempo tem algumas funcionalidades interessantes para utilizao em combinao com os canais. Ele contm 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 so entregues. / / Contm campos filtrados ou no exportadas ... } O tempo de intervalo especificado ns (em nanossegundos como um int64) especificado como uma varivel do tipo durante Durao no time.NewTicker funo de fbrica: func NewTicker(dur) *Ticker
CURSO GRATUITO
Ele pode ser muito til quando, durante a execuo de alguma coisa goroutines (log de um estado, uma impresso, de um clculo, 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 instruo SELECT:
ticker := time.NewTicker(updateInterval) defer ticker.Stop( ) ... select { case u:= <- ch1: case v:= <- ch2: ... case <- ticker.C: logState(status) / / chama alguma funo de registro logState default: / / nenhum valor pronto para ser recebido ... } A funo time.Tick ( ) com a assinatura funo Tick (d Durao) <-chan Tempo til quando voc s precisa de acesso ao canal de retorno e no precisa desligar -lo: ele envia o tempo no canal de retorno com periodicidade d, que um nmero de nanossegundos. Handy para usar quando voc tem que limitar a taxa de processamento por unidade de tempo, como no seguinte trecho de cdigo (o cliente funo. import time rate_per_sec := 10 var dur Duration = 1e9 / rate_per_sec chRate := time.Tick(dur) / / um carrapato cada 1/10th de um segundo for req := range requests { <- chRate / / Taxa de limitar nossas chamadas Service.Method RPC go client.Call(Service.Method, req, ...) } O efeito lquido que os novos pedidos podem apenas so tratados taxa indicada: os blocos de canal chRate taxas mais elevadas. A taxa por segundo pode ser aumentada ou diminuda de acordo com a carga e /ou os recursos da mquina. Um tipo de temporizador parece exatamente o mesmo como um tipo Ticker (ela construda com NewTimer (d mas ele envia o tempo apenas uma vez, aps uma durao d. Existe tambm uma funo time.After (d) com a assinatura: func After(d Duration) < -chan Time Aps Durao 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 tambm ilustra muito bem a clusula padro no select:
CURSO GRATUITO
boom := time.After(5e8) for { select { case <-tick: fmt.Println(tick.) case <-boom: fmt.Println(BOOM!) return default: fmt.Println( .) time.Sleep(5e7) } } } / * Sada: . tick. . . tick. . . tick. . . tick. . . tick. BOOM! */ IDIOM: padro de tempo limite Simples Queremos receber de um ch canal, mas quero esperar no mximo 1 segundo para o valor chegar. Comece criando um canal de sinalizao e lanar 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 instruo SELECT para receber a partir de qualquer ch ou timeout: se nada chega ao cho em um perodo 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 ocorreu case <-timeout: / / A leitura de ch expeirou break } Segunda variante: Abandonar chamadas sncronas que funcionam muito longo: Poderamos tambm 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 execuo de goroutines. Quando,
CURSO GRATUITO
no seguinte trecho de cdigo que client.Call no 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 necessrio para evitar impasse de goroutines e garantir a coleta de lixo do canal de timeout. 3 variante: Suponha que temos um programa que l a partir de vrios 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 funo recebe uma slice de conexes de banco de dados e uma seqncia 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, ento o primeiro valor a chegar sero recuperados, independentemente da ordem de execuo. Um goroutine execuo sempre pode ser interrompido pelo telefone runtime.Goexit( ) Cache de dados em aplicaes: 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 memria, porque recuperar um valor de um banco de dados uma operao custosa, quando o valor do banco de dados no muda, no 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 invlido (j expeirou) e ns no queremos que a nossa aplicao para apresentar um valor antir para o usurio. Usando recuperar com goroutines
Uma aplicao 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) {
CURSO GRATUITO
defer func( ) { if err := recover( ); err != nil { log.Printf(work failed with %s in %v:, err, work) } }( ) do(work) } No trecho de cdigo 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 funo diferido, cdigo diferido pode chamar rotinas de biblioteca que se utilizam de panic e recuperar sem falhar. Como exemplo, a funo adiada em safelyDo ( ) pode chamar uma funo de log antes de chamar recuperar, e que o cdigo de registro correria afetado pelo estado em panic. Com o nosso padro de recuperao no local, a funo do (e qualquer coisa que chama) pode sair de qualquer situao ruim limpa chamando panic. Mas a recuperao tem que ocorrer dentro do goroutine em panic: ele no pode ser recuperado por um goroutine diferente.
Suponha que ns temos que executar uma srie de tarefas, uma tarefa executada por um trabalhador (processo). Uma tarefa pode ser definido como uma estrutura (os detalhes concretos no so importantes aqui): type Task struct { / / Algum estado } 1 (antir) paradigma: usar a memria compartilhada para sincronizar O conjunto de tarefas compartilhada da memria;, a fim de sincronizar o trabalho e evitar condies de corrida, temos que guardar a piscina com um bloqueio Mutex: type Pool struct { Mu sync.Mutex Tasks [ ]Task } A sync.Mutex um bloqueio de excluso mtua: ela serve para proteger a entrada de uma seo crtica em cdigo: apenas um goroutine (thread) pode entrar que a seo de uma vez. Se mais de um goroutine seria permitido, uma condio de corrida pode existir: a estrutura exterior no podia mais ser atualizados corretamente. No modelo tradicional (aplicado na maioria dos OO -lnguas clssicas como C + +, Java, C #), o processo de trabalho poderia ser codificado como: func Worker(pool *Pool) { for { pool.Mu.Lock( ) / / Comeam seo crtica: task := pool.Tasks[0] pool.Tasks = pool.Tasks[1:] / / Fim da seo crtica pool.Mu.Unlock( ) process(task) } }
Muitos desses processos de trabalho poderiam ser executados simultaneamente, pois eles certamente
CURSO GRATUITO
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 atribuda a um e apenas um processo. Se o bloqueio no 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 no faria obter uma tarefa, algumas tarefas seria obtida por vrios trabalhadores. Essa sincronizao de bloqueio funciona bem para alguns processos de trabalho, mas se a piscina muito grande e vamos atribuir um grande nmero de processos para trabalhar com ele, a eficincia do processamento ser diminuda pela sobrecarga do mecanismo de lock-unlock. Este o gargalo: o desempenho certamente Ir diminuir quando o nmero de trabalhadores aumenta, drasticamente em um determinado limite. 2 paradigma: canais Agora canais de tarefas so 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 nmero N deve ser ajustada ao nmero de tarefas. A rotina principal, que realiza a funo 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 } } No h bloqueio: o processo de obteno de uma nova tarefa no envolve disputa. Se a quantidade de tarefas aumenta, o nmero de trabalhadores pode ser aumentada em conformidade e desempenho que no se degrada to mal quanto na primeira soluo. Do canal pendente h, naturalmente, apenas 1 cpia na memria, mas no h conteno, porque a primeira Trabalhador para chegar primeira tarefa pendente simplesmente leva-lo (leitura e envio de um canal so operaes atmicas: ver 14.2.2 ) e process -lo completamente. impossvel prever quais tarefa ser executada pela qual o processo, e vice -versa. Com um nmero crescente de trabalhadores, h tambm um aumento da comunicao sobrecarga, que tem um pequeno impacto no desempenho. Neste exemplo simples, talvez seja difcil ver a vantagem do segundo modelo, mas as aplicaes com situaes-bloqueio complexos so muito difceis de programar e de acertar, e uma grande parte dessa complexidade no software no necessrio em uma soluo que se aplica o segundo modelo. Assim, no s o desempenho uma grande vantagem, mas o cdigo mais claro e elegante , talvez, uma vantagem ainda maior. sem dvida uma forma idiomtica Go de trabalhar:
CURSO GRATUITO
out <- t } } Para qualquer problema que pode ser modelado como tal paradigma Master -Worker, uma soluo anloga com os trabalhadores como goroutines comunicam atravs de canais e o Mestre como coordenador seria um ajuste perfeito. Se o sistema distribui ao longo de vrias mquinas, um nmero de mquinas pode executar as goroutines Trabalhadores, eo Mestre e trabalhadores pudessem se comunicar entre si atravs netchan ou rpc. O que usar: a sync.Mutex ou de um canal? Embora neste captulo, sublinhou insistentemente goroutines usando canais porque isso muito novo em idiomas do sistema, isso no significa que a abordagem clssica com bloqueio agora tabu: Go tem tanto e d-lhe a escolha de acordo com o problema a ser resolvido : construir a soluo que o desempenho mais elegante, simples e de fcil leitura, e na maioria dos casos vai seguir automaticamente. No tenha medo de usar um Mutex se que se encaixa o seu problema melhor. Go pragmtico em deix-lo usar as ferramentas que resolver o seu problema melhor e no for -lo em um estilo de cdigo. Como uma regra geral: uso de bloqueio (mutexes), quando: cache informaes em uma estrutura de dados compartilhada segurando informaes de estado, que o contexto ou o estado do aplicativo em execuo usecanais quando: comunicando resultados assncronos distribuio de unidades de trabalho passando propriedade dos dados Se voc encontrar suas regras de bloqueio esto ficando muito complexo, pergunte -se se o uso do canal (s) no pode ser mais simples.
Um gerador uma funo que retorna o prximo valor em uma seqncia cada vez que a funo chamada, como: generateInteger( ) => 0 generateInteger( ) => 1 generateInteger( ) => 2 .... um produtor que s retorna o prximo valor, no a seqncia inteira, o que chamado de avaliao preguiosa: s calcular o que voc precisa no momento, poupando recursos valiosos (memria e CPU): uma tecnologia para a avaliao de expresses na demanda. Um exemplo seria a gerao de uma seqncia interminvel de nmeros pares: para ger-la e, em seguida, usar os nmeros um a um seria talvez difcil e certamente no Iria caber na memria! Mas uma funo simples por tipo com um canal e uma goroutine pode fazer o trabalho. package main import ( fmt ) var resume chan int func integers( ) chan int {
CURSO GRATUITO
yield := make (chan int) count := 0 go func ( ) { for { yield <- count count++ } }() return yield } func generateInteger( ) int { return <-resume } func main( ) { resume = integers( ) fmt.Println(generateInteger( )) / /=> 0 fmt.Println(generateInteger( )) / /=> 1 fmt.Println(generateInteger( )) / /=> 2 }
Uma diferena subtil que o valor lido a partir do canal poderia ter sido gerado algum tempo atrs, no gerada no momento da leitura. Se voc precisa de um tal comportamento, voc tem que implementar um mecanismo de solicitao-resposta. Quando a tarefa do gerador computacionalmente caro eo fim de gerar resultados, no importa, em seguida, o gerador pode ser paralelizado internamente usando goroutines. Mas tome cuidado para que a sobrecarga gerada pela desova muitos goroutines no superam qualquer ganho de desempenho. Estes princpios podem ser generalizada: por meio da utilizao inteligente da interface vazia, fechamentos e funes de alta ordem, podemos implementar um BuildLazyEvaluator construtor genrico para a funo de avaliao preguiosa (isto deve melhor colocado dentro de um pacote de utilitrios). O construtor tem uma funo que tem de ser avaliado e um estado inicial como argumentos e retorna uma funo sem argumentos retornando o valor desejado. A funo de avaliao passou tem de calcular o prximo valor de retorno, bem como o prximo estado com base no argumento do Estado. Dentro do construtor de um canal e uma goroutine com um loop infinito so criados. Os valores de retorno so transmitidos para o canal a partir do qual eles so obtidos pela a funo retornou para uso posterior. Cada vez que um valor buscado o prximo vai ser calculado. No prximo exemplo, este aplicado atravs da definio de um whitch evenFunc preguiosamente gera nmeros pares: Em main( ), criamos os primeiros 10 nmeros pares, a cada novo convite ao mesmo ( ) retorna o prximo. Para isso, teve de se especializar a nossa funo de construo em geral BuildLazyIntEvaluator, em seguida, fomos capazes de definir at mesmo em cima disso.
package main import ( 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 {
CURSO GRATUITO
retValChan := make(chan Any) loopFunc := func( ) { var actState Any = initState var retVal Any for { retVal, actState = evalFunc(actState) retValChan <- retVal } } retFunc := func( ) Any { return <-retValChan } go loopFunc( ) return retFunc } func BuildLazyIntEvaluator(evalFunc EvalFunc, initState Any) func( ) int { ef := BuildLazyEvaluator(evalFunc, initState) return func( ) int { return ef( ).(int) } } / * Sada: 0th even: 0 1th even: 2 2th even: 4 3th even: 6 4th even: 8 5th even: 10 6th even: 12 7th even: 14 8th even: 16 9th even: 18 */
Futuros de execuo
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 so fceis de implementar via encerramentos e goroutines, a idia semelhante aos geradores, com exceo 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 atravs de uma funo inversa (m), e, em seguida, levar o produto de ambos os resultados. Isto poderia ser feito com a seguinte funo 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 clculo do b_inv? Estes clculos 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:
CURSO GRATUITO
func InverseProduct(a Matrix, b Matrix) { a_inv_future := InverseFuture(a) b_inv_future := InverseFuture(b) a_inv := <-a_inv_future b_inv := <-b_inv_future return Product(a_inv, b_inv) }
onde InverseFuture( ) lana uma tampa tal como uma goroutine, o que coloca a array inversa resultante num futuro canal como resultado: 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 amigvel. Alm disso, os futuros pode ser exposto atravs de uma verso assncrona do API. Desta forma, o paralelismo em seu pacote pode ser levantado no cdigo do usurio com o mnimo esforo. Multiplexing Aplicaes cliente-servidor o tipo de aplicaes onde goroutines e canais de brilhar. Um cliente pode ser qualquer programa em execuo em qualquer dispositivo que precisa de algo a partir de um servidor, ento 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 situao tpica h muitos clientes (tantos pedidos) e um (ou alguns) servidores. Um exemplo que usamos o tempo todo o navegador do cliente, que solicita uma pgina web. Um servidor web responde enviando a pgina web de volta para o navegador. Em Go um servidor Ir normalmente executam uma resposta a um cliente em um goroutine, portanto, um goroutine lanado para cada solicitao do cliente. A tcnica comumente usada que o prprio cliente-pedido contm 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 Solicitao } Ou de modo mais geral: type Reply struct { ... } type Request struct { arg1, arg2, arg3 some_type replyc chan *Reply } Continuando com a forma simples, o servidor poderia lanar para cada pedido uma corrida function ( ) em um goroutine que Ir aplicar um op operao do tipo binOp aos ints e, em seguida, enviar o resultado no canal de resposta: type binOp func(a, b int) int func run(op binOp, req *Request) { req.replyc <- op(req.a, req.b) }
CURSO GRATUITO
A rotina de servidor laos para sempre, receber pedidos a partir de uma solicitao chan * e, para evitar o bloqueio devido a uma operao de longa durao, iniciando uma goroutine para cada solicitao 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); } } O servidor iniciado em seu prprio goroutine pelo startServer funo: 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 solicitaes so 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-- { / / No 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 cdigo pode ser encontrado na Listagem, a sada : Request 99 is ok! Request 98 is ok! ... Request 1 is ok! Request 0 is ok! Done Este programa s comea 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 so: se quisermos comear a mesma quantidade de fios de reais, o programa trava rapidamente.
CURSO GRATUITO
package main import fmt type Request struct { a, b int replyc chan int / / resposta do canal dentro da Solicitao } type binOp func(a, b int) int func run(op binOp, req *Request) { req.replyc <- op(req.a, req.b) } func server(op binOp, service chan *Request) { for { req := <-service / / pedidos chegam aqui / / Inicia goroutine para pedido: go run(op, req) / / no 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 = 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 } / / verifica: for i := N - 1; i >= 0; i-- { / / No 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 subdiviso: desligar o servidor por um canal de sinalizao Na verso anterior, o servidor no faz um desligamento normal quando principal retorna, ele forado 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 funo do servidor, em seguida, usa uma seleo para escolher entre o canal de servio e sair canal: func server(op binOp, service chan *request, quit chan bool) { for {
CURSO GRATUITO
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. 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 cdigo completo pode ser encontrado em multiplex_server2.go, com o mesmo resultado. package main import fmt type Request struct { a, b replyc chan int / / resposta do canal dentro da Solicitao } type binOp func(a, b int) int func 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-- { / / doesnt matter what order if <-reqs[i].replyc != N+2*i { fmt.Println(fail at, i)
CURSO GRATUITO
} else { fmt.Println(Request , i, is ok!) } } quit <- true fmt.Println(done) }
Isto facilmente conseguido atravs de um canal com um tampo , cuja capacidade o nmero mximo de solicitaes simultneas. O max_tasks.go programa no faz nada til, mas contm a tcnica para fazer exatamente isso: no mais do que pedidos MAXREQS sero tratadas e processadas simultaneamente, porque quando o buffer do canal SEM completo, os blocos de funo do punho e no outro pedido pode comear , at que um pedido seja removido sem. SEM age como um semforo, um termo tcnico para uma varivel de sinalizador em um programa que sinaliza uma certa condio. package main const ( 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) { / / Faa alguma coisa / / Pode demorar muito tempo e usar muita memria ou CPU } func handle(r *Request) { process(r) / / Sinal feito: permitir prxima solicitao para comear / / Fazendo um lugar vazio no buffer <-Sem } func Server(queue chan *Request) { for { sem <- 1 / / bloqueia quando o canal est cheio (1000 pedidos so ativos) / / So esperar aqui at que haja capacidade para processar um pedido / / (No importa o que colocamos nele) request := <-queue go handle(request) } } func main( ) { queue := make(chan *Request) go Server(queue) } Desta forma, a aplicao efectua uma utilizao ptima de um recurso limitado tal como a memria, tendo goroutines sincronizar o seu uso de recursos que usando um canal tamponada (o canal usado como um semforo).
CURSO GRATUITO
goroutines Encadeamento
A seguir chaining.go-programa de demonstrao demonstra mais uma vez o quo fcil para iniciar um grande nmero de goroutines. Aqui isso acontece em um loop para -in principal.Aps 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 tambm demonstra como o nmero de goroutines podem ser dadas na linha de comando e analisado atravs flag.Int, por exemplo, encadeando -n = 7000 gera 7000 goroutines. package main import ( 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 concluso fmt.Println(x) / / 100000, aprox. 1,5 s } paralelizao um clculo ao longo de vrios ncleos
Suponha que temos nmero NCPU de ncleos de CPU: const NCPU = 4 / / por exemplo, 4 para um processador quadqore e queremos dividir a computao em partes NCPU, cada um rodando em paralelo com os outros. Isso poderia ser feito de forma esquemtica (deixamos de lado os parmetros 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 NCPU for i := 0; i < NCPU; i++ { <-Sem / / Espera por uma tarefa para completar } / / Tudo feito. } func DoPart (SEM chan int) { / / Faz a parte da computao } SEM <- 1 / / Sinal que esta pea feita } func main( ) { runtime.GOMAXPROCS = NCPU DoAll( ) }
CURSO GRATUITO
- A funo DOALL ( ) faz com que um canal sem juros no qual cada uma das computaes paralelas vai sinalizar a sua concluso, em um para goroutines NCPU lao so iniciados, cada um realizando 1/NCPU - parte do trabalho total. Cada goroutine DoPart( ) sinaliza a sua concluso em sem. - DOALL ( ) espera em um loop for at que todos os goroutines NCPU ter concludo: o canal sem juros funciona como um semforo, o cdigo mostra um padro tpico de semforo. No modelo atual do tempo de execuo, voc tambm tem que definir GOMAXPROCS para NCPU. Paralelizao uma computao atravs de uma grande quantidade de dados
Suponha que temos de processar um grande nmero de itens -de dados independentes uns dos outros, entrando atravs de uma no canal, e quando completamente processado colocar em um canal fora, muito parecido com um gasoduto de fbrica. O processamento de cada item de dados -provavelmente tambm envolvem uma srie de etapas: Preprocess / STEPA / o passo B / .../ PostProcess Um algoritmo pipelining seqencial tpico para resolver este execuo 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 sequncia: o processamento do segundo item no iniciado antes do primeiro item ps -processada eo resultado colocado no canal para fora. Se voc pensar sobre isso, voc vai logo perceber que este um gigantesco desperdcio de tempo. Um clculo muito mais eficiente seria a de deixar que cada trabalho etapa de processamento independentes um do outro como um goroutine.Cada passo obtm os dados de entrada do canal de sada 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 computaes paralelas: go PreprocessData(in, preOut) go ProcessStepA(preOut, stepAOut) go ProcessStepB(stepAOut, stepBOut) go ProcessStepC(stepBOut, stepCOut) go PostProcessData(stepCOut, out } As capacidades tampo canais poderia ser utilizada para optimizar ainda mais o processo inteiro.
Para salvaguardar modificaes concorrentes de um objeto em vez de usar o bloqueio com um Mutex sync tambm podemos usar um goroutine backend para a execuo seqencial de funes annimas. No programa seguinte, temos um tipo de pessoa que agora contm um CHF campo, um canal de funes annimas. Este inicializado no construtor mtodo NewPerson, que tambm inicia um mtodo de
CURSO GRATUITO
back-end ( ) como um mtodo goroutine.This executa em um loop infinito de todas as funes colocado no CHF, efetivamente serializao los e, assim, proporcionar o acesso simultneo seguro. Os mtodos que mudam e recuperar o salrio fazer uma funo annima que faz isso e colocar essa funo no ICC, e backend ( ) Ir execut-las seqencialmente. Observe como no mtodo Salrio a funo de fechamento criado inclui o canal fChan. Este , naturalmente, um exemplo simplificado e no deve ser aplicada em tais casos, mas mostra como o problema poderia ser enfrentado em situaes mais complexas. package main import ( fmt 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.50 Salary changed: Person - name is: Smith Bill - salary is: 4000.25 */
CURSO GRATUITO
No texto anterior, s vezes advertido com! ... ! por uso indevido Go. Ento no se esquea de olhar para a seo especfica no livro sobre o assunto quando se deparar com uma dificuldade em uma situao como essa codificao. Aqui est uma viso geral de armadilhas para a sua convenincia, referindo -se ao local onde voc pode encontrar mais explicaes e exemplos:
Nunca use var p * a no confundir declarao de ponteiro e de multiplicao Nunca mude a contra-varivel 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 esquea ( ) depois de uma funo de nome (captulo 6), especificamente ao chamar um mtodo em um receptor ou chamando uma funo lambda como um goroutine Nunca use new ( ) com mapas, sempre se Ao codificar um mtodo ( ) String para um tipo, no use fmt.Print ou iguais no cdigo Nunca se esquea de usar Flush ( ) quando terminar a escrita tamponado Nunca ignore os erros, ignor-los pode levar a falhas no programa No use variveis globais ou de memria compartilhada, eles fazem o seu cdigo no seguro para a execuo de simultaneamente Use println apenas para fins de depurao
Inicializar uma slice de mapas da maneira certa Sempre use a vrgula, forma ok (ou marcada) para o tipo de afirmaes Faa e inicializar os seus tipos com uma fbrica Use um ponteiro como receptor para um mtodo em um struct apenas quando o mtodo modifica a estrutura, caso contrrio, use um valor
Neste captulo vamos montar alguns dos erros mais comuns ou-no est no Go-programao. Ns muitas vezes referem-se a explicao completa e exemplos nos captulos anteriores. Leia os ttulos de pargrafo como o que voc no deve fazer!
var remember bool = false if something { remember := true / / Errado. } / / Uso lembrar No trecho anterior do cdigo a varivel lembrar nunca se tornar realidade fora do corpo if. Se algo verdadeiroo, dentro do corpo, se uma nova varivel lembrar que esconde o exterior lembrar declarado por causa de: =, e no ser verdade. Mas aps o encerramento} de se lembrar recupera o seu valor externo falsa. Ento escreva-o como: if something { remember = true } Isso tambm pode ocorrer com um loop for, e pode ser particularmente sutil em funes com variveis de retorno nomeados, conforme o trecho a seguir mostra:
CURSO GRATUITO
func shadow( ) (err error) { x, err := check1( ) / / x criado; err atribudo a if err != nil { return / / errar corretamente retornou } if y, err := check2(x); err != nil { / / err y e interior so criados return } else { fmt.Println(y) } return }
strings abusar.
Quando voc precisa fazer um monte de manipulaes em uma string, mente que strings em Go (como em Java e C #) so imutveis. Concatenaes de string do tipo a + = b so ineficientes, especialmente quando realizada dentro de um loop. Eles causam inmeros realocaes e cpia de memria. Em vez disso, deve-se usar um bytes.Buffer acumular contedo da string, como no seguinte trecho: var b bytes.Buffer ... for condition { b.WriteString(str) / / Anexa string str para o buffer } return b.String( )
Observao: Devido a compilador-optimizaes e, dependendo do tamanho das cadeias usando um tampo de s comea a tornar-se mais eficiente quando o nmero de iteraes > 15.
Suponha que voc est processando uma srie de arquivos em um loop for, e voc quer certificar -se de que os arquivos so fechados aps o processamento usando defer, como este: for _, file := range files { if f, err = os.Open(file); err != nil { return } / / Isto /errado/. O arquivo no fechado quando esta iterao do loop termina. defer f.Close( ) / / Executar operaes em f: f.Process(data) } Mas no estreitol da defer para-loop no executado, de modo que os arquivos no esto 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
CURSO GRATUITO
} / / Executar operaes em f: f.Process(data) / / Fecha f: f.close ( ) } Defer s executado no retorno de uma funo, e no 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 parmetro para uma funo provavelmente o que voc sempre quis saber: passando um ponteiro para uma varivel a ser capaz de mud-lo, e no passar uma cpia dos dados. Ento voc quer fazer isso: func findBiggest( listOfNumbers [ ]int ) int { } No isso: func findBiggest( listOfNumbers *[ ]int ) int { } No desreferenciava uma slice quando usado como parmetro!
Olhe para o seguinte programa: Nexter uma interface com um mtodo next( ) significado ler o prximo byte.nextFew1 tem este tipo de interface como parmetro e l os prximos bytes num, devolv -los como uma slice: isso ok. No entanto nextFew2 usa um ponteiro para o tipo de interface como parmetro: quando utilizar a funo seguinte ( ), obtemos um erro de compilao claro: n.next indefinido (tipo * Nexter no tem campo ou mtodo seguinte)
package main import ( 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!
CURSO GRATUITO
Passar um valor como um parmetro em uma funo ou como receptor de um mtodo pode parecer um desvio de memria, porque um valor sempre copiado. Mas, por outro lado valores so alocados na pilha, que rpido 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 realizao de um objeto, e vai passar esse objeto para a pilha, assim tambm causando uma alocao de memria adicional: portanto, nada foi ganho no uso de uma ponteiro em vez do valor!
Olhe para o seguinte cdigo: package main import ( fmt time ) var values = [5]int{10, 11, 12, 13, 14} func main( ) { / / Verso A: for ix := range values { / / Ix o ndice func( ) { fmt.Print(ix, ) }() / / Encerramento de chamadas, imprime cada ndice } fmt.Println ) / / Verso 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) / / Verso C: o caminho certo for ix := range values { go func(ix interface{ }) { fmt.Print(ix, ) }(ix) } fmt.Println( ) time.Sleep(5e9) / / Verso D: imprimir os valores: val := values[ix] go func( ) { fmt.Print(val, ) }() } time.sleep(1e9) } / * Resultado: 01234 44444 10342 10 11 12 13 14 */
CURSO GRATUITO
Verso A chama 5 vezes um fechamento que imprime o valor do ndice, verso B faz o mesmo, mas invoca cada fechamento como um goroutine, argumenting que este seria mais rpido porque o fechamento executar em paralelo. Se deixar tempo suficiente para todos os goroutines para executar, a sada de verso B : 4 4 4 4 4. Por que isso? A varivel ix no circuito acima B na verdade uma nica varivel que assume o ndice de cada elemento da array. Porque os fechamentos so todos apenas obrigado a que uma varivel, h uma boa chance de que quando voc executar este cdigo, voc ver o ltimo ndice (4) impresso para cada iterao em vez de cada ndice em seqncia, porque os goroutines provavelmente no iniciar a execuo at que o loop, quando ix tem o valor 4. O caminho certo para codificar esse ciclo a verso C: invocar cada fechamento com ix como parmetro. IX , em seguida, avaliado em cada iterao e colocado na pilha para o goroutine, de modo que cada ndice est disponvel para o goroutine quando eventualmente executado. Note -se que a sada pode ser 0 1 2 3 4 ou 0 3 1 2 4 ou . . . , Dependendo de quando cada um dos goroutines pode comear. Na verso D que imprimir os valores da array, por que esse trabalho e verso B no tem? Porque as variveis declaradas dentro do corpo de um loop (como aqui val) no so partilhadas entre iteraes, e, portanto, pode ser usado separadamente em um encerramento. erro no tratamento de erro No use booleanos: Fazendo uma varivel booleana cujo valor um teste no erro de condio como na seguinte suprfluo: var good bool / / Teste para um erro, bem se torna verdadeiroo ou falso if !good { return errors.New(things arent good) } Teste sobre o erro de imediato: ... err1 := api.Func1( ) if err1 != nil { ... } No desorganizao seu cdigo com verificao de erros: Evite escrever cdigo 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 funes em uma instruo de inicializao do if 's. Mas, mesmo assim, os erros so relatados (por imprimi-los) com instrues if espalhados por todo o cdigo. Com este padro, difcil dizer o que a lgica normal do programa e qual a verificao de erros / relatrios. Note tambm que a maior parte do cdigo dedicado a condies de erro em qualquer ponto do cdigo. Uma boa soluo envolver as condies de erro em um fechamento, sempre que possvel, como no exemplo a seguir: func httpRequestHandler(w http.ResponseWriter, req *http.Request) { err := func ( ) error { if req.Method != GET {
CURSO GRATUITO
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( ) ... Essa abordagem separa claramente a verificao de erros, o relatrio de erros, ea lgica 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) Nmero de bytes em uma string str: len (str) Nmero de caracteres em uma string str: MAIS RPIDO: utf8.RuneCountInString(str) len ([ ] int (str)) (5) A concatenao de strings: MAIS RPIDO: com um bytes.Buffer Strings.Join( ) += (6) Como analisar os argumentos da linha de comando: usar o pacote de sistema operacional ou flag
CURSO GRATUITO
Arrays e slices
Fazer:
arr1 := new([len]type) slice1 := make([ ]type, len) arr1 := [...]type{i1, i2, i3, i4, i5} arrKeyValue := [len]type{i1: val1, i2: val2} var slice1 [ ]type = arr1[start:end]
Inicializao:
(1) Como cortar o ltimo elemento de uma array ou linha slice: line = line[:len(line) -1] (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 := false Found: for row := range arr2Dim { for column := range arr2Dim[row] if arr2Dim[row][column] == V found = true break Found } } }
(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 excluso de uma chave em um mapa: delete(map1, key1)
Structs
CURSO GRATUITO
Fazer: type struct1 struct { field1 type1 field2 type2 ... } ms := new(struct1) Inicializao: ms := &struct1{10, 15.5, Chris} Capitalizar a primeira letra do nome da estrutura para torn -lo visvel do lado de fora da embalagem. Muitas vezes, melhor para definir uma funo de factory para a estrutura, e forar 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 #%ds type is unknown\n, i) } } }
Funes
Como usar recuperar para parar um panic terminando sequencial: func protect(g func( )) { defer func( ) { log.Println(done)
CURSO GRATUITO
/ / 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: 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 tampo 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:
CURSO GRATUITO
Uma regra de ouro, se voc usar o paralelismo para ganhar eficincia sobre computao em srie: a quantidade de trabalho realizado dentro goroutine tem que ser muito maior do que os custos associados criao goroutines e envio de dados e para trs entre eles. 1 - Utilizando canais buffer para o desempenho: Um canal tamponada pode facilmente dobrar a sua produo, dependendo do contexto, o ganho de desempenho pode ser 10x ou mais. Voc pode ainda tentar otimizar ajustando o capacidade do canal. 2 - A limitao do nmero de itens em um canal e embal -los em arrays: Canais se tornar um gargalo se voc passar um monte de itens individuais atravs deles. Voc pode contornar isso atravs da embalagem blocos de dados em arrays e, em seguida, a descompactao do outro lado. Isso pode ser um ganho de velocidade de um fator de 10x. Fazer: ch := make(chan type, buf)
(1) Como lao 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 condio for { if input, open := <-ch; !open { break } fmt.Printf(%s , input) } Ou uso (1), onde a deteco automtica. (3) Como usar um canal para que o programa principal esperar at o goroutine completa? (Padro 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 no importa. }() doSomethingElseForAWhile ( ) <-Ch / / Espera goroutine terminar; descartar valor enviado. Se a rotina deve bloquear para sempre, omitir ch <- 1 a partir da funo lambda. (4) Canal padro de fbrica: a funo uma fbrica de canal e inicia uma funo lambda como goroutine preencher o canal func pump( ) chan int { ch := make(chan int) go func( ) { for i := 0; ; i++ { ch <- i } }( ) return ch }
CURSO GRATUITO
(5) Simples padro timeout: timeout := make(chan bool, 1) go func( ) { time.Sleep(1e9) / / um segundo timeout <- true }() select { case <-ch: / / A leitura de ch ocorreu case <-ch: / / A leitura de ch expeirou } (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 } }