O que há de Novo?
Fórum Outer Space - O maior fórum de games do Brasil

Registre uma conta gratuita hoje para se tornar um membro! Uma vez conectado, você poderá participar neste site adicionando seus próprios tópicos e postagens, além de se conectar com outros membros por meio de sua própria caixa de entrada privada!

  • Anunciando os planos GOLD no Fórum Outer Space
    Visitante, agora você pode ajudar o Fórum Outer Space e receber alguns recursos exclusivos, incluindo navegação sem anúncios e dois temas exclusivos. Veja os detalhes aqui.


Eu fui testar a Go aqui, e olhe no que deu.

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
Q6jTBe4.jpg


A grana tá apertada, Netflix há tempos cancelada, e o torresmo comendo solto aqui em casa. Praticamente só me alimento de torresmo. Devido a isso, acabo que muitas das coisas que baixo vem com legendas sem sincronia com o vídeo em questão, então, ou eu fico igual um corno procurando novas legendas internet afora ou uso alguma ferramenta para alterar a sincronia delas.

Há um bom tempo que eu uso o site http://subshifter.bitsnbites.eu para sincronizar os meus arquivos SRT. O problema que ele é um pouco chato pra fazer isso, então, há dois domingos resolvi eu mesmo criar a minha própria ferramenta de sincronia de legendas. Fui na velha e boa wiki para ver como era o formato padrão dos arquivos SRT e começar a programar a minha própria ferramenta em C/C++, mas no meio do processo, meu de uma epifania e me perguntei: "Por que não dou uma olhadinha naquela linguagem da Google e ver como ela funciona, quem sabe fique legal fazer esse programinha nela."

Então o motivo de criar um pequeno programa para ajustar a legenda seria já suficiente para eu começar a estudar Go. O que eu sabia sobre a linguagem eram apenas duas coisas: que ela era compilada (igual a C/C++) e que ela era feita pela Google, fora isso nunca tinha visto nada sobre a linguagem, o que seria um bom desafio em começar a estudá-la e no mesmo dia já criar alguma coisa útil nela.

O.o Go me ameaçou com uma metralhadora na mão:kwow

Depois de uns 30 minutos da instalação, estava eu todo pimpão começando a estudar e escrever o meu projeto quando de repente ao testá-lo o Go me dá uma facada no peito, tipo a que Bolsonaro tomou na barriga. Eu olhei o código e não tinha nenhum erro aparente, até que ao rodá-lo no terminal novamente, percebo que a linguagem reclamou e gerou um erro de compilação de uma variável que declarei e não utilizei, fiquei chocado com isso, ao mesmo tempo que fiquei bastante intrigado porque nunca tinha visto uma linguagem de programação reclamar disso.

Na Golang você só declara aquilo que você for usar, se colocar alguma variável e não utilizá-la, um erro de compilação é gerado. Isso é de fato legal porque você sabe que seu programa nunca terá variáveis inutilizadas, força na marra uma boa prática de programação que até mesmo coders veteranos deixa passar.

Toolchain super simples de mexer, sem o stress da compilação em C/C++

Calma, não vou aqui abandonar C/C++, na verdade, nem posso fazer isso. E eu adoro C/C++. Mas como a Golang é uma linguagem compilada, comparações com a linguagens clássicas não poderia deixar de serem feitas.

Logo de cara uma coisa que percebi e me animou demais foi a facilidade de se compilar um projeto na Go. Depois de seu projeto estar configurado na workspace, o resto fica super fácil de mexer. Quem trabalhou com C/C++ além do nível trivial, precisando adicionar várias libs e ferramentas internas e externas, sabe que é uma bagunça desgraça fazer o seu projeto funcionar com tudo interligado. Ainda mais se você estiver usando o CMake para isso. Na Go é tudo bem simples e intuitivo, depois de mais de 1h, eu já estava adicionando libs thirds usando apenas o comando go get -u -v <endereço GitHub da lib> em qualquer lugar do terminal e o toolchain da Go já baixava no lugar certo e já deixava pronto para a minha IDE enxergar e eu conseguir adicionar no meu projeto sem problema nenhum.

Onde diabos estão as classes?

Nesse aspecto a Go se assemelha mais a C que a C++. Não há classes, não há hierarquia como conhecemos, não há necessidade de encapsulamento, não há overloading e overriding de métodos e membros, enfim, a linguagem é rápida e caceteira eliminando muita coisa que linguagens como Java, C# e C++ usam e abusam.

Afinal, isso é bom ou ruim? Depende. Depende do que você for fazer e de como você for programar. Eu tive que adaptar algumas lógicas para funcionar da forma como a linguagem Go funciona. Há, no entanto, uma estrutura de de armazenamento de informações que se assemelha ao struct da linguagem C que, inclusive, se chama struct também na Go.

Você tem métodos e funções, e ambas funcionam um pouco diferente. Assim como ocorre no C++ que há as duas coisas, na Go também há, porém, na C apenas há functions.

Então, landinho, se a Go não é uma linguagem orientada a objetos, então, POR QUE diabos ela usa método e não fica apenas com funções como é em C?

A resposta é simples, é porque ela não é C :D

Go herda sim algumas características híbridas de outras linguagens, ela não consegue ser uma linguagem puramente procedural como é a C, e no caso dos seus métodos são usados em conjunto com seus Structs e até onde vi apenas restritos a eles.

Podemos usar o conceito de interface na Go (funciona de uma forma um pouco diferente do conceito de interface na linguagem Java). Já que a linguagem não tem generics :ksnif as interfaces podem fazer um pouco dessa papel, mas nada perto dos templates que podemos usar no C++ que é extremamente poderoso e versátil, porém, extremamente complicado de se masterizar.

bkv3xbjb74epempcjone.gif


Landinho, já que a Go é uma linguagem que compila, então tem acesso ao baixo nível como em C/C++? Posso usar ponteiros e referência de memória? Como fica a questão de gerenciamento de memória?

Mesmo a linguagem possuindo ponteiros e referência, o uso deles é descorajado pela documentação oficial da Google. Até onde onde eu vi, a linguagem não dá acesso total ao baixo nível como C/C++ dá. Prova disso é que eu não tenho controle onde devo gravar os valores das minhas variáveis. C/C++ são tão poderosas que eu escolho onde e como gravar meus próprios dados (por isso também há uma avalanche de coisas para se fazer uma mesma coisa nessas duas linguagens O.o).

Em C/C++ eu posso escolher se uma variável ficará armazenada na stack ou na heap ou jogá-la até na VRAM da minha placa de vídeo se assim eu quiser. Posso gravar os dados aonde eu quiser. Na Go existe um GC (Garbage Collection), assim como há em linguagens como C# e Java, portanto o gerenciamento das variáveis e suas memórias ficam ao encargo do próprio controlador da linguagem, isso gera vantagens e desvantagens. As instâncias criadas pelo operador new terão controle pela GC automaticamente e não dá pra saber onde e como a Go tá gerenciando isso.

Uma curiosidade: Toda a arquitetura do gerenciador de memória da Go (o seu GC) foi escrita estritamente na linguagem C. Já a parte de frontend da linguagem foi feita, por sua vez, na linguagem C++.

Calma, amiguinho, não veremos os códigos doidão em Go como existem em C/C++ :D ex:

C++:
//socorro, man!!!
void(*change)(int&) = varDaEmossaum;

void forEach(const std::vector<int>& array, void(*func)(const int&) = nullptr)
{
    if (func)
        for (const int& value : array)
        {
            func(value);
        }
}

C++:
//socorro, help, me tire daqui!!!
    char array[size+1];

    template <int I, int ... indices>
    constexpr string(char const (&str) [I], detail_::indices<Indices...>): array{str[indices]..., '\0'}{}

Se eu não posso manipular a memória do jeito como eu quiser, onde fica o poder da Go?

A Go veio para facilitar o uso da criação de aplicações multithreading, sendo uma linguagem voltado para isso. Então, a Go se torna uma ótima opção para criação de programas de servidor e daqueles que fazem uso excessivo de vários processadores.

Na Go não existe threads da mesma forma como em outras linguagens. Aqui existem as goroutines que funcionam para isso e são bem versáteis e poderosas.

Bom, chega de rodeios e falar apenas da linguagem e mostrar um pouquinho da prática dela.

NOTA: Codificação do fórum colocada como linguagem C, mas o código é Go. Fiz isso porque o fórum não tem suporte para Golang.

C:
package main

/**
Autor: LandStalker (inocencio)
Data: 02/09/2018
Descricao: Programa para adicionar ou subtrair tempo nas legendas em formato SRT
           Uso: ./submanager -file:<arquivo_legenda.srt> -time=<tempo_em_ms>
           Ex.: ./submanager -file:"lawrence of arabia.srt" -time=-2000

EN Version: This is a short program to increment or reduce srt subtitle files. To use it call this program passing
these arguments ./submanager -file:<file.srt> -time=<time in ms>

Make sure you entered time argument as millesecond. Positive value will increase the time to subtitle shows up and
negative value will decrese this time instead.

                                        `:+shhso+/
                 ``                  ./hddy+..:/+o.
             `/osyyso+/:`          -odNdhy+  .yNd-+:
           .oddhhdddhysooso/-`  `-smmhs+//:   -oh-/+:
          /hdysdhs+/. `-yo+smhyyhmNNmdhhhhyso+/-` ohh:
        `-mhyyhmo///   -dMo--/////+syyss+///:/+osyydmNo.
    ````-ddysyms+///.`  .-.`-/+osys/:-:.``:so.```..-:+yso/.
`:sdddhyNysyhN//////:.````-/syo/-```:so.``.:.`````````-+sh+`
.ymdyyhmNmsshdy///////////+sy+-.``````..``````````.-:+oooosys:
hmhyddhdmdsshd+//////////ys+-``````````........-/oys+/-..``.so:
Mdhhm-.+ddsyhh////////+sh+-```.-/+ooooooooossso+/-.`````````:ss
Mhhdd``+dhshhy///////oss-``.-/oo+:--------....``````````````.oy.
Ndhhm-.+dhsdho/////+ys/.`.+ss/-.`````````````````````````````+y/
omdhhmdmmhsdy+////oh+--/os/-.````````````````````````````````+h+
+hmddmNNdsdh+//+sh/:oso:..``````````````````````````````````+y-
  `-+oosymshhy/oyyoso/-`````````````````````````````````````.oy
       `:Nyyhdhddy+-.```````````````````````````````````````:so
        .dhysymms:.````````````````````````````````````````.sy+
         .Nhyssyhhho:..`````````````````````````.--:://+osshdmy
          +hdyssssyyyyo+-..````````````...-:+osyyyyhhyyyyhddyo-
           :sddhyysssyyyhys+:.`````-:/oshdddhhhysssssyhhdh+`
            `.-oyyhhhhhyyyyhhhdhhhdhhhhhhhyyyyyhhhhhhyy/-`
                  `-:/+oyhddddddddddddhhyysso+////:-.
*/

import (
    "bufio"
    "bytes"
    "flag"
    "fmt"
    "os"
    "path/filepath"
    "strconv"
    s "strings"
    "time"

    "github.com/logrusorgru/aurora"
)

var srtfilepath string

type TextPart struct {
    num   string
    time  string
    lines []string
}

func main() {

    isNotFlag := false

    timePtr := flag.Int("time", 0, "O tempo é dado em millisegundos (1000ms = 1s) "+
        "Valores acima de 0 atrasa a legenda, abaixo de 0, adianta.")
    filePtr := flag.String("file", "", "Nome do arquivo SRT.")

    flag.Parse()

    //fmt.Print(aurora.Green(">> SubStr Manager v0.1 <<\n\n").Bold())
    fmt.Println(aurora.Colorize(">> SubStr Manager v0.1 <<", aurora.GrayFg|aurora.GreenBg|aurora.BoldFm))

    if *timePtr == 0 {
        fmt.Println(aurora.Red("Informe um 'time'. Ex: -time=-1000"))
        isNotFlag = true
    }

    if *filePtr == "" {
        fmt.Println(aurora.Red("Informe um 'file'. Ex: -file=\"minha legenda.srt\""))
        isNotFlag = true
    }

    if isNotFlag {
        os.Exit(1)
    }

    ex, err := os.Executable()
    checkError(err)

    fmt.Println("CDir:          ", aurora.Cyan(filepath.Dir(ex)))
    fmt.Println("Time:          ", aurora.Cyan(*timePtr), aurora.Cyan("ms"))
    fmt.Println("File:          ", aurora.Cyan(*filePtr))

    srtfilepath = *filePtr

    if s.HasSuffix(srtfilepath, ".srt") {
        //todos os parametros OK? Entao converte o tempo do arquivo SRT.
        strShifter(srtfilepath, *timePtr)
    } else {
        //arquivo invalido
        fmt.Println(aurora.Red("Error: O arquivo "), srtfilepath, aurora.Red(" não é uma extensão srt."))
    }
}

func (p *TextPart) convertTime(timestamp int) {
    times := s.Split(p.time, "-->")
    p.time = ""

    for counter, e := range times {
        timesdiv := s.Split(s.TrimSpace(e), ",")

        var hours int
        var minutes int
        var seconds int
        var ms int
        var err error

        for i, _e := range timesdiv {
            if i == 0 {
                //time completo
                t := s.Split(_e, ":")

                for j, v := range t {
                    if j == 0 {
                        //hora
                        hours, err = convertStrToInt(v)
                    } else if j == 1 {
                        //minuto
                        minutes, err = convertStrToInt(v)
                    } else {
                        //segundo
                        seconds, err = convertStrToInt(v)
                    }

                    checkError(err)
                }
            } else {
                //restante em millisegundos
                ms, err = convertStrToInt(_e)
                //cria uma data no padrao Go Lang
                result := time.Date(2018, 9, 7, hours, minutes, seconds, 0, time.UTC)
                //adiciona os millisegundos restantes a data criada
                result = result.Add(time.Duration(ms) * time.Millisecond)
                result = result.Add(time.Duration(timestamp) * time.Millisecond)

                //formata o tempo ja convertido para o padrao do formato SRT com base num padrao definido
                //ref: https://golang.org/pkg/time/#example_Time_Format
                formattedTime := s.Replace(result.Format("15:04:05.000"), ".", ",", 1)

                if counter > 0 {
                    p.time += " --> "
                }

                //adiciona o tempo convertido no lugar do anterior
                p.time += formattedTime
            }
        }
    }
}

/**
Converte uma string em inteiro.
@param srt
*/
func convertStrToInt(str string) (int, error) {
    return strconv.Atoi(str)
}

/**
Ajusta o tempo em millesegundos da legenda. Valores positivos, aumenta o tempo da legenda em relação ao
vídeo enquanto valores negativos reduz o tempo da legenda.
*/
func strShifter(filename string, timestamp int) {
    file, err := os.Open(filename)
    checkError(err)
    defer file.Close()

    //variaveis
    scanner := bufio.NewScanner(file)
    var line string
    var text []string
    var parts []TextPart
    partCounter := 0
    i := 0
    isNewPart := true
    textPart := new(TextPart)

    //le o arquivo linha a linha (para leitura direta usa-se ioutil.ReadFile(filename) no lugar)
    for scanner.Scan() {
        //pega a linha corrente do arquivo
        line = scanner.Text()

        //cria um novo trecho
        if isNewPart {
            i++
            isNewPart = false
            partCounter = 0
            textPart = new(TextPart)
        }

        //novo trecho do arquivo?
        if len(line) == 0 {
            textPart.lines = text
            text = nil

            //salva o trecho atual no slice
            parts = append(parts, *textPart)
            isNewPart = true
            continue
        }

        if partCounter == 0 {
            //0 = numeracao da legenda
            textPart.num = line
            partCounter = 1
        } else if partCounter == 1 {
            //1 = tempo da legenda
            textPart.time = line
            partCounter = 2
        } else if partCounter == 2 {
            //2 = linha(s)
            text = append(text, line)
        }
    }

    fmt.Println("Parts:         ", aurora.Cyan(i))

    //formata o texto de saida para o arquivo de saida
    var buffer bytes.Buffer
    br := "\n"

    for _, e := range parts {
        e.convertTime(timestamp)

        buffer.WriteString(e.num + br)
        buffer.WriteString(e.time + br)
        fmt.Println("entrada")

        for _, _e := range e.lines {
            buffer.WriteString(_e + br)
        }

        buffer.WriteString(br)
    }

    //cria o arquivo
    file, err = os.Create(srtfilepath)
    //escreve no arquivo criado
    n, err := file.Write(buffer.Bytes())
    file.Sync()

    fmt.Println("Written Bytes: ", aurora.Cyan(n))
}

func checkError(e error) {
    if e != nil {
        panic(e)
    }
}
 
Ultima Edição:

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
O código acima deixei no seguinte repositório: https://github.com/inocencio/submanager

Ainda não cheguei a testar programação de jogos em Go. Quando eu tiver mais tempo e conseguir fazer algo, eu posto aqui. O problema é que não uso PC e aqui jogos ficam uma coisa extremamente limitada.
 

linkmau

Ei mãe, 500 pontos!
Mensagens
777
Reações
1.621
Pontos
574
Top d+ seu tópico, sempre que possível compartilhe seus conhecimentos relacionados a C e C++(direto e indiretamente)...perfavore
 

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
Obrigado, Link.

Eu tive que falar do C/C++ porque são linguagens que em parte a Go "ataca", tentando pegar um pouco do nicho que as linguagens clássicas trabalham. Ainda estou conhecendo a Go, é muito interessante mesmo sendo mais limitada que C/C++.
 

j0kk3r

Mil pontos, LOL!
VIP
Mensagens
12.352
Reações
16.925
Pontos
1.284
Legal, e curto muito fazer esse tipo de coisa também. Masssssss sobre a linguagem, sou programador Java, então só tive vários tiques durante o texto. Não ser orientada a objetos por exemplo já me incomodou bastante
 

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
Legal, e curto muito fazer esse tipo de coisa também. Masssssss sobre a linguagem, sou programador Java, então só tive vários tiques durante o texto. Não ser orientada a objetos por exemplo já me incomodou bastante

Eu trabalhei muito com Java que é uma linguagem estritamente OOP, tirando os tipos primitivos é tudo objeto.

Confesso pra você que estranhei um pouco no início também, mas a linguagem é tranquila de se trabalhar, exige um pouco de formulação de organização de arquivos já que funciona de uma forma diferente de Java e C#, sendo mais perto do C mas sem a dificuldade da mesma.
 


j0kk3r

Mil pontos, LOL!
VIP
Mensagens
12.352
Reações
16.925
Pontos
1.284
Eu trabalhei muito com Java que é uma linguagem estritamente OOP, tirando os tipos primitivos é tudo objeto.

Confesso pra você que estranhei um pouco no início também, mas a linguagem é tranquila de se trabalhar, exige um pouco de formulação de organização de arquivos já que funciona de uma forma diferente de Java e C#, sendo mais perto do C mas sem a dificuldade da mesma.

Mas deve depender muito do uso né. Orientação à objetos é bom demais
 

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
Mas deve depender muito do uso né. Orientação à objetos é bom demais

A estrutura funciona mais ou menos assim:

Todo arquivo pertence a um pacote (package) sendo que, em toda a sua aplicação, caso ela seja um executável e não uma lib, terá obrigatoriamente um pacote do tipo main
Código:
package main
e uma função main, até aí é bem parecido com qualquer outra linguagem.

Depois, qualquer outro arquivo extra .go em sua aplicação poderá pertencerá a packages de nomes diferentes, mais de um arquivo pode pertencer a um package (sendo main ou não) e eles podem estar numa mesma pasta, caso assim ocorra, quando você for importá-los, para a linguagem é como se você estivesse importando um único arquivo e não arquivos diferentes, porque você acaba importando packages e não arquivos.

Em Java, os packages funcionam para nomear as pastas, então se eu tenho um pacote com.outerspace.forum eu tenho a pasta /com/outerspace/forum e quando importo, importo as classes(arquivos) que estão em seus pacotes.

Você tem structs que funciona já parecido com o struct do C e do C#, seria o substituto para uma class já que a linguagem não tem. Então não se pode usar características como herança, polimorfismo, sobrecarga e sobrecarregamento de métodos, mas eu posso usar encapsulamento, inclusive, a linguagem permite em certo nível a visibilidade de membros (variáveis e métodos), assim como ocorre em linguagens tipicamente OO.

Essa visibilidade funciona de um modo muito peculiar da linguagem Go que acho que não existe em nenhum outra. Exemplo: eu posso declarar uma variável na forma padrão tanto em camelCase quanto PascalCase, o compilador na hora interpretará o membro declarado a partir da notação que você aplicou:

Código:
//variável string que fica restrita ao package
var tortinhasBeijaMeninos string

//variável string que fica visível além do package
var TortinhasBeijaMeninos string

//essa é uma função que somente o package pode ver
func chinasAtacamOS() { ... }

//essa é uma função que fica visível além do package
func ChinasAtacamOS() { ... }

//é um struct restrito ao package
struct outerspaceUser { ... }

//é um struct não restrito ao package
struct OuterspaceUser { ... }

//esse é um método que somente o package pode ver
func (p *OuterspaceUser) AdicionarLarva(nome string, anusDeForum int) { ... }

//esse é um método que somente o package pode ver
func (p *OuterspaceUser) adicionarLikes() { ... }

Mesmo a linguagem não apresentando herança propriamente dita como numa linguagem OO. Você pode usar interfaces para criar tipos iguais de um mesmo objeto, você não pode herdá-los mas pode simular um tipo em comum. Uma interface pode ser usada em Go para simular também uma forma mais primitiva de Generics (cuidado que, ao mesmo tempo, ela não é uma Generics).

Esse tutorial fala um pouco do uso das interfaces e de como a Go consegue lidar bem com a ausência de classes.

Outra coisa que a linguagem tem e incentiva muito é o uso de funções com múltiplos retornos. Ex:

Código:
//o método GetListaUsuarios retorna duas variáveis
func (p *Outerspace) GetListaUsuarios() {
    var list = make([]string, 10, 1000)
    var err error
    ...
    ...
    return list, err
}

minhaLista, err := outerspace.GetListaUsuarios()

Eu sei que há como simular isso em outras linguagens, no C# usa-se as keywords ref e out, já no C++ é só passar os parâmetros como referência(&) ou como ponteiro(*). Na verdade em ambas as linguagens eu não tenho um retorno pelo método mas sim pelos parâmetros de entrada. Algumas linguagens de banco de dados permitem algo semelhante também, a exemplo da PL/SQL usada no Oracle.

Bom, acho que escrevi muita coisa. Fique à vontade para perguntar e falar a respeito da linguagem. Eu ainda estou noob nela, quase todo o dia acabo programando alguma coisa e tentar melhor o meu conhecimento a respeito.
 

j0kk3r

Mil pontos, LOL!
VIP
Mensagens
12.352
Reações
16.925
Pontos
1.284
A estrutura funciona mais ou menos assim:

Todo arquivo pertence a um pacote (package) sendo que, em toda a sua aplicação, caso ela seja um executável e não uma lib, terá obrigatoriamente um pacote do tipo main
Código:
package main
e uma função main, até aí é bem parecido com qualquer outra linguagem.

Depois, qualquer outro arquivo extra .go em sua aplicação poderá pertencerá a packages de nomes diferentes, mais de um arquivo pode pertencer a um package (sendo main ou não) e eles podem estar numa mesma pasta, caso assim ocorra, quando você for importá-los, para a linguagem é como se você estivesse importando um único arquivo e não arquivos diferentes, porque você acaba importando packages e não arquivos.

Em Java, os packages funcionam para nomear as pastas, então se eu tenho um pacote com.outerspace.forum eu tenho a pasta /com/outerspace/forum e quando importo, importo as classes(arquivos) que estão em seus pacotes.

Você tem structs que funciona já parecido com o struct do C e do C#, seria o substituto para uma class já que a linguagem não tem. Então não se pode usar características como herança, polimorfismo, sobrecarga e sobrecarregamento de métodos, mas eu posso usar encapsulamento, inclusive, a linguagem permite em certo nível a visibilidade de membros (variáveis e métodos), assim como ocorre em linguagens tipicamente OO.

Essa visibilidade funciona de um modo muito peculiar da linguagem Go que acho que não existe em nenhum outra. Exemplo: eu posso declarar uma variável na forma padrão tanto em camelCase quanto PascalCase, o compilador na hora interpretará o membro declarado a partir da notação que você aplicou:

Código:
//variável string que fica restrita ao package
var tortinhasBeijaMeninos string

//variável string que fica visível além do package
var TortinhasBeijaMeninos string

//essa é uma função que somente o package pode ver
func chinasAtacamOS() { ... }

//essa é uma função que fica visível além do package
func ChinasAtacamOS() { ... }

//é um struct restrito ao package
struct outerspaceUser { ... }

//é um struct não restrito ao package
struct OuterspaceUser { ... }

//esse é um método que somente o package pode ver
func (p *OuterspaceUser) AdicionarLarva(nome string, anusDeForum int) { ... }

//esse é um método que somente o package pode ver
func (p *OuterspaceUser) adicionarLikes() { ... }

Mesmo a linguagem não apresentando herança propriamente dita como numa linguagem OO. Você pode usar interfaces para criar tipos iguais de um mesmo objeto, você não pode herdá-los mas pode simular um tipo em comum. Uma interface pode ser usada em Go para simular também uma forma mais primitiva de Generics (cuidado que, ao mesmo tempo, ela não é uma Generics).

Esse tutorial fala um pouco do uso das interfaces e de como a Go consegue lidar bem com a ausência de classes.

Outra coisa que a linguagem tem e incentiva muito é o uso de funções com múltiplos retornos. Ex:

Código:
//o método GetListaUsuarios retorna duas variáveis
func (p *Outerspace) GetListaUsuarios() {
    var list = make([]string, 10, 1000)
    var err error
    ...
    ...
    return list, err
}

minhaLista, err := outerspace.GetListaUsuarios()

Eu sei que há como simular isso em outras linguagens, no C# usa-se as keywords ref e out, já no C++ é só passar os parâmetros como referência(&) ou como ponteiro(*). Na verdade em ambas as linguagens eu não tenho um retorno pelo método mas sim pelos parâmetros de entrada. Algumas linguagens de banco de dados permitem algo semelhante também, a exemplo da PL/SQL usada no Oracle.

Bom, acho que escrevi muita coisa. Fique à vontade para perguntar e falar a respeito da linguagem. Eu ainda estou noob nela, quase todo o dia acabo programando alguma coisa e tentar melhor o meu conhecimento a respeito.

Entendi um pouco da estrutura, mas me parece mais bizarro ainda. Principalmente pelo modo de trabalhar a visibilidade dos métodos e variáveis... me parece muito suscetível a erros.

Provavelmente a linguagem é ótima, afinal estamos falando de Google né, mas só brincando com ela pra saber.

Eu não tinha reparado nas datas do projeto e do tópico até hoje. Vi que já tem pelo menos uns 20 dias que você tá mexendo com a linguagem.. e se ainda tá postando sobre ela é pq gostou hehehe.

Fez mais alguma coisa, ou parou no projeto das legendas?
 

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
Entendi um pouco da estrutura, mas me parece mais bizarro ainda. Principalmente pelo modo de trabalhar a visibilidade dos métodos e variáveis... me parece muito suscetível a erros.

Provavelmente a linguagem é ótima, afinal estamos falando de Google né, mas só brincando com ela pra saber.

Eu não tinha reparado nas datas do projeto e do tópico até hoje. Vi que já tem pelo menos uns 20 dias que você tá mexendo com a linguagem.. e se ainda tá postando sobre ela é pq gostou hehehe.

Fez mais alguma coisa, ou parou no projeto das legendas?

Por enquanto estou fazendo projetos para atender às minhas necessidades.

Atualmente estou fazendo um programa para terminal para acessar os meus arquivos do Google Drive, dessa forma, eu não preciso necessariamente entrar no site drive.google.com para acessar os arquivos. Acessar esses arquivos vai ficar de forma análoga a acessar os arquivos normais do seu computador, usa-se o comando ls/dir para listar, cd para entrar na pasta, view para visualizar, dl para baixar e por aí vai.

O intuito é visualizar, baixar, subir e sincronizar os dados de forma direta via terminal.

Mais pra frente, para um outro projeto, vou adicionar os recursos do Google Drive para fazer backup automáticos.

O nome desse projeto é GGDrive, por enquanto tá ficando assim:

vC6e4V7.png


goY1V6i.png
 

Macaco Louco

Ei mãe, 500 pontos!
Mensagens
1.394
Reações
1.086
Pontos
608
A linguagem é muito poderosa, mas acho a sintaxe estranha demais. Acho que estou muito acostumado ao C e ao Python. Irei acompanhar seus projetos.


Enviado do meu iPhone usando Tapatalk
 

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
Um códigozinho que criei ano passado para pegar os links de OnePiece de um site para mim:

C:
package main

/**
Autor: LandStalker
Data: 02/10/2018
Descricao: Programa para pegar os links do OnePiece EX

                                        `:+shhso+/
                 ``                  ./hddy+..:/+o.
             `/osyyso+/:`          -odNdhy+  .yNd-+:
           .oddhhdddhysooso/-`  `-smmhs+//:   -oh-/+:
          /hdysdhs+/. `-yo+smhyyhmNNmdhhhhyso+/-` ohh:
        `-mhyyhmo///   -dMo--/////+syyss+///:/+osyydmNo.
    ````-ddysyms+///.`  .-.`-/+osys/:-:.``:so.```..-:+yso/.
 `:sdddhyNysyhN//////:.````-/syo/-```:so.``.:.`````````-+sh+`
.ymdyyhmNmsshdy///////////+sy+-.``````..``````````.-:+oooosys:
hmhyddhdmdsshd+//////////ys+-``````````........-/oys+/-..``.so:
Mdhhm-.+ddsyhh////////+sh+-```.-/+ooooooooossso+/-.`````````:ss
Mhhdd``+dhshhy///////oss-``.-/oo+:--------....``````````````.oy.
Ndhhm-.+dhsdho/////+ys/.`.+ss/-.`````````````````````````````+y/
omdhhmdmmhsdy+////oh+--/os/-.````````````````````````````````+h+
 +hmddmNNdsdh+//+sh/:oso:..``````````````````````````````````+y-
  `-+oosymshhy/oyyoso/-`````````````````````````````````````.oy
       `:Nyyhdhddy+-.```````````````````````````````````````:so
        .dhysymms:.````````````````````````````````````````.sy+
         .Nhyssyhhho:..`````````````````````````.--:://+osshdmy
          +hdyssssyyyyo+-..````````````...-:+osyyyyhhyyyyhddyo-
           :sddhyysssyyyhys+:.`````-:/oshdddhhhysssssyhhdh+`
            `.-oyyhhhhhyyyyhhhdhhhdhhhhhhhyyyyyhhhhhhyy/-`
                  `-:/+oyhddddddddddddhhyysso+////:-.
*/

import (
    "bytes"
    "fmt"
    "github.com/gocolly/colly"
    "html/template"
    "os"
    "strings"
    _ "strings"
)

type Episode struct {
    Title  string
    SD     string
    HD     string
    SDMega string
    HDMega string
}

type OnePiece struct {
    Saga     string
    Episodes []Episode
}

var onepiece *OnePiece
var files []string

func doDOM(e *colly.HTMLElement) {
    for _, n := range e.DOM.Nodes {
        fmt.Println("Node:", n.Data)
        for _, a := range n.Attr {
            fmt.Println("\tAttr:", a.Key, " - ", a.Val)
        }
    }
}

func hasDOMKeyValue(e *colly.HTMLElement, key string, value string) bool {
    for _, n := range e.DOM.Nodes {
        for _, a := range n.Attr {
            if a.Key == key && a.Val == value {
                return true
            }
        }
    }

    return false
}

func checkRealLink(url string) {
    c := colly.NewCollector(colly.AllowURLRevisit())

    //a[href]
    c.OnHTML("#centro", func(e *colly.HTMLElement) {
        fmt.Println(e.Text)
        //link := e.Request.AbsoluteURL(e.Attr("href"))
        //fmt.Println("URL:", link)
    })

    c.OnRequest(func(r *colly.Request) {
        fmt.Printf("L %s...\n", r.URL.String())
    })

    c.Visit(url)
}

func processSiteRequest() {
    c := colly.NewCollector(colly.AllowURLRevisit())
    files = make([]string, 1)

    episodes := make([]Episode, 1)
    onepiece = &OnePiece{}
    onepiece.Episodes = episodes
    onepiece.Saga = "Primeira Saga"

    c.OnHTML(".episodiov5", func(e *colly.HTMLElement) {
        episode := Episode{}
        ep := e.DOM.Find(".titulo strong").Text()
        desc := e.DOM.Find(".online-header").Find("h2").Text()

        episode.Title = ep + " - " + desc

        desc = strings.Replace(desc, "!", "! ", 1)
        desc = strings.Replace(desc, "?", " ", -1)
        desc = strings.Replace(desc, ",", "", -1)
        desc = strings.Replace(desc, "/", "-", -1)
        desc = strings.TrimSpace(desc)

        files = append(files, fmt.Sprintf("%s - %s", ep, desc))

        fmt.Printf("%s - %s\n", ep, desc)

        e.ForEach("nav", func(i int, nav *colly.HTMLElement) {
            nav.ForEach("ul", func(i int, ul *colly.HTMLElement) {
                ul.ForEach("li", func(i int, li *colly.HTMLElement) {
                    a := li.DOM.Find("a").First()

                    if strings.TrimSpace(a.Text()) == "SD" || strings.TrimSpace(a.Text()) == "HD" {
                        //servidor próprio
                        link, ok := li.DOM.Find(".opex-server").Attr("href")
                        if ok {
                            //fmt.Printf("\t%s - %s\n", a.Text(), link)

                            if strings.TrimSpace(a.Text()) == "SD" {
                                episode.SD = link
                            } else if strings.TrimSpace(a.Text()) == "HD" {
                                episode.HD = link
                            }
                        }

                        //mega upload
                        link, ok = li.DOM.Find(".linkpadrao").Attr("href")
                        if ok {
                            if strings.TrimSpace(a.Text()) == "SD" {
                                episode.SDMega = "https://onepiece-ex.com.br" + strings.TrimSpace(link)
                            } else if strings.TrimSpace(a.Text()) == "HD" {
                                episode.HDMega = "https://onepiece-ex.com.br" + link
                            }
                        }
                    }
                })
                fmt.Println()
            })
        })
        //salva OnePiece na lista
        episodes = append(episodes, episode)
        onepiece.Episodes = episodes
    })

    c.OnRequest(func(r *colly.Request) {
        fmt.Printf("Obtendo os Links %s...\n", r.URL.String())
    })

    c.OnResponse(func(r *colly.Response) {
        fmt.Println("Status:", r.StatusCode)
    })

    c.Visit("https://onepiece-ex.com.br/episodios/t03/")
    c.Wait()
    writeFile()
}

func writeFile() {
    checkErr := func(err error) {
        if err != nil {
            panic(err)
        }
    }

    file, err := os.Create("eps.txt")
    defer file.Close()
    checkErr(err)

    var b bytes.Buffer
    br := "\n"

    for _, e := range files {
        b.WriteString(e + br)
    }

    n, err := file.Write(b.Bytes())
    checkErr(err)
    file.Sync()

    fmt.Printf("\nArquivo '%s' salvo com %d bytes.\n", file.Name(), n)

    //template
    oFile, err := os.Create("onepice.html")
    checkErr(err)
    defer oFile.Close()

    t, err := template.New("template.html").ParseFiles("template.html")
    checkErr(err)

    err = t.Execute(oFile, onepiece)
    checkErr(err)
    fmt.Printf("\nArquivo template '%s' salvo com sucesso.\n", oFile.Name())
}

func main() {
    fmt.Printf("OnePiece EX...\n\n")
    processSiteRequest()
}
 

Landstalker

Lenda da internet
Mensagens
19.355
Reações
39.658
Pontos
1.584
Como tô abrindo vários projetos no GitHub, acaba que fica chato de ter que pegar o nome do diretório e procurar no git a página do projeto. Então, para atender isso, criei uma rotina em Golang para fazer isso automaticamente com 0 estresse para mim, basta no terminal estar no diretório do projeto e digitar "ogit" (nome do programinha que criei, quase um acrônimo de open github) e ele abre a URL correta do projeto.

Também estou criando um outro programa em Golang para me ajudar a criar os zilhões de arquivos em CMake para eu compilar os projetos em C/C++. CMake é coisa do cão.

C:
package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "os/exec"
    "runtime"
    "strings"
)

func checkErr(err error) {
    if err != nil {
        log.Fatal(err)
        panic(err)
    }
}

func getURL(filename string) string {
    file, err := os.Open(filename)
    checkErr(err)
    defer file.Close()

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        line := strings.TrimSpace(scanner.Text())
        tokens := strings.Split(line, "=")

        if len(tokens) > 1 {
            if strings.TrimSpace(strings.ToLower(tokens[0])) == "url" {
                return strings.TrimSpace(tokens[1])
            }
        }

    }

    return ""
}

func openBrowser(filepath string) {
    var err error
    var url string

    filepath += "/config"
    url = getURL(filepath)

    if len(url) == 0 {
        panic("It was unable to parse URL.")
    }

    fmt.Printf("Opening %s...\n", url)

    switch runtime.GOOS {
    case "linux":
        err = exec.Command("xdg-open", url).Start()
    case "windows":
        err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
    case "darwin":
        err = exec.Command("open", url).Start()
    default:
        err = fmt.Errorf("unsupported platform")
    }

    checkErr(err)
}

func main() {
    cDir, err := os.Getwd()
    checkErr(err)

    //check if path is a valid hidden github folder
    var path = cDir + "/.git"
    fi, err := os.Stat(cDir)
    checkErr(err)

    if fi.IsDir() {
        openBrowser(path)
    }
}
 

iamnotarobot

Novato
Mensagens
2
Reações
1
Pontos
13
Curto Go demaaaais ! É muito simples e produtivo. E ao mesmo tempo performa bem. Tenho tentado aprender Rust tbm, mas "sem muito sucesso" ghashuash.
 
Topo Fundo