1 pontos por GN⁺ 2 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • Esta versão melhora literais de struct e inferência de tipos com foco em métodos genéricos, além de adicionar recursos práticos à biblioteca padrão, ao runtime e à toolchain
  • Com alocação de memória especializada por tamanho, o custo de algumas alocações abaixo de 80 bytes cai em até 30%; em programas intensivos em alocação, espera-se cerca de 1% de ganho de desempenho e aumento de cerca de 60 KB no binário
  • encoding/json/v2 passa a ser oferecido oficialmente, e o encoding/json existente também usa internamente o v2; foram adicionados o pacote padrão de UUID e assinaturas ML-DSA baseadas em FIPS 204
  • O perfil goroutineleak, rótulos do pprof em traceback, synctest.Sleep para tempo virtual e um servidor HTTP de teste em memória facilitam diagnóstico e testes de concorrência
  • Canais de timer sem buffer, drenagem automática do corpo de resposta HTTP e restrições mais rígidas em //go:linkname podem afetar código existente, então é preciso verificar a compatibilidade antes da migração para o Go 1.27

Linguagem e sistema de tipos

  • O principal destaque do Go 1.27, os métodos genéricos, permitem declarar parâmetros de tipo próprios, independentes do receiver
    • Antes, só funções de nível superior podiam ser genéricas, então até operações ligadas a tipos precisavam ser escritas como funções de pacote
    • Agora é possível definir como método operações como Box[T].Map[U], que retornam um tipo de elemento diferente do de entrada
    • Interfaces ainda não podem declarar métodos com parâmetros de tipo, e também não é possível implementar interfaces com métodos genéricos
  • As chaves de literais de struct agora podem usar não só nomes de campos de nível superior, mas também seletores de campo válidos
    • Em structs embutidas, campos promovidos podem ser inicializados diretamente, como em User{ID: 7}
  • A inferência de tipos de função foi ampliada para conversões e literais compostos
    • Em []func([]int) int{first, last}, os argumentos de tipo de funções genéricas são inferidos com base no tipo de função esperado
    • Antes, era necessário instanciar explicitamente, como em first[int] e last[int]

Runtime e desempenho

  • O compilador passa a chamar rotinas de alocação especializadas por tamanho, reduzindo em até 30% o custo de algumas alocações de memória menores que 80 bytes
    • Em programas reais intensivos em alocação, o ganho total esperado de desempenho é de cerca de 1%
    • Não exige alterações no código, mas o binário cresce cerca de 60 KB independentemente da carga de trabalho
    • Pode ser desativado com GOEXPERIMENT=nosizespecializedmalloc, mas essa opção será removida no Go 1.28
  • Foram adicionadas três otimizações de compilador ativadas por padrão
    • Um pass de fluxo de dados de bits conhecidos que rastreia bits sabidamente 0 ou 1 para eliminar operações redundantes
    • Movimentação de código invariante de laço, que leva para fora do loop cálculos que não mudam durante a repetição
    • Compilação de switch compatíveis em tabelas de consulta, incluindo fallthrough
  • O experimental GOEXPERIMENT=mapsplitgroup altera o layout de memória de grupos de map de KVKVKVKV para KKKKVVVV, mas permanece desativado por padrão
  • O linker move descritores de tipo e itabs para uma seção dedicada .go.type e remove typelinks e itablinks
    • Como reflect.typelinks passa a retornar tipos em vez de offsets, bibliotecas que acessam esse símbolo via //go:linkname podem ser afetadas

Diagnóstico de goroutines e profiling

  • Módulos cujo go.mod indica Go 1.27 ou superior passam a mostrar rótulos de runtime/pprof no cabeçalho de goroutines em traceback
    • Contextos anexados com pprof.Do, como {request: 42}, aparecem em crash dumps, SIGQUIT e na saída de runtime.Stack
    • Para evitar que rótulos sensíveis apareçam em traceback, continua possível usar GODEBUG=tracebacklabels=0
  • O detector de vazamento de goroutines, que era experimental no Go 1.26, foi promovido ao perfil oficial goroutineleak
    • Ele executa GC para encontrar goroutines que nunca poderão progredir, como em canais ou mutexes, e imprime as pilhas
    • Em serviços, pode ser coletado pelo endpoint /debug/pprof/goroutineleak sem necessidade de GOEXPERIMENT

Criptografia e identificadores

  • O novo pacote crypto/mldsa implementa a assinatura pós-quântica ML-DSA do FIPS 204
    • Os três conjuntos de parâmetros MLDSA44, MLDSA65 e MLDSA87 equilibram tamanho de chave/assinatura e nível de segurança
    • ML-DSA também foi adicionado a chaves e assinaturas de crypto/x509 e aos esquemas de assinatura TLS 1.3 de crypto/tls
  • O novo pacote padrão uuid gera e analisa UUIDs RFC 9562 com números aleatórios criptograficamente seguros
    • uuid.New() escolhe um método adequado para uso geral, NewV4() gera UUID puramente aleatório e NewV7() gera UUIDs em ordem de criação
    • UUIDs compostos por parte aleatória são comparáveis, então == pode ser usado diretamente
    • UUID v7, ordenável por tempo, é adequado para chaves de banco de dados

APIs de JSON e processamento de dados

  • encoding/json/v2 e o encoding/json/jsontext de baixo nível são disponibilizados sem GOEXPERIMENT=jsonv2
    • O encoding/json v1 existente também passa a usar internamente a implementação v2
    • Exceto por parte do texto de algumas mensagens de erro, o comportamento anterior é mantido, então não é necessária migração
    • Se houver problema de compatibilidade, é possível restaurar a implementação original v1 com GOEXPERIMENT=nojsonv2
    • Por desempenho, o v2 não ordena chaves de map por padrão, então testes que exigem saída estável devem definir json.Deterministic
  • strings.CutLast e bytes.CutLast dividem um valor com base no último delimitador
    • Se não houver delimitador, retornam a entrada inteira, uma parte final vazia e false
  • O genérico Hasher[T] de hash/maphash define em conjunto a estratégia de hash e igualdade de valores
    • Valores iguais devem obrigatoriamente ter o mesmo hash
    • É fornecido ComparableHasher[T] para tipos comparáveis, e também é possível implementar estratégias customizadas, como strings case-insensitive
  • math/big.Int.Divide calcula quociente e resto ao mesmo tempo, aplicando um modo de arredondamento explícito entre Trunc, Floor, Round e Ceil
    • Como o resto também muda conforme o arredondamento, isso complementa em código financeiro e numérico a limitação de truncamento em direção a zero de Quo e Mod
  • math/rand/v2.(*Rand).N gera números aleatórios limitados por faixa para tipos inteiros arbitrários ou duration, usando sua própria fonte *Rand

SIMD portável

  • O pacote experimental simd oferece uma API SIMD independente do tamanho do vetor e é ativado com GOEXPERIMENT=simd
    • Em ambientes compatíveis, ele é compilado para instruções vetoriais reais de hardware; caso contrário, usa emulação pura em Go
    • O número de lanes de tipos como Float32s não é fixo e segue a largura de hardware de cada máquina
  • A biblioteca padrão já usa internamente intrinsics simd/archsimd
    • MemHash32, MemHash64 e StrHash do map Swiss Table foram reimplementados com a nova base SIMD

Testes determinísticos

  • testing/synctest.Sleep avança o tempo virtual e espera até que todas as goroutines estabilizem em uma só operação
    • Dentro de um bubble do synctest, o tempo real não passa, então até uma espera de 2 segundos termina imediatamente
    • Isso substitui código repetitivo que combinava time.Sleep com synctest.Wait
  • httptest.NewTestServer executa o servidor em uma rede virtual em memória em vez de uma porta TCP real
    • srv.Client() se conecta diretamente ao handler por pipes internos ao processo
    • Como a limpeza é automática com t.Cleanup, não é necessário defer srv.Close()
    • Combinado com testing/synctest, isso permite testar ida e volta HTTP em tempo virtual com rapidez e determinismo

Rede e mudanças de compatibilidade

  • Os canais retornados por time.After, time.NewTimer, time.NewTicker e afins passam a ser sempre canais síncronos sem buffer
    • A opção asynctimerchan de GODEBUG, que restaurava o comportamento antigo com buffer, foi removida
  • Em HTTP/1, http.Response.Body.Close lê de forma conservadora o corpo ainda não consumido para ajudar no reaproveitamento da conexão
    • Se você dependia de Close para encerrar cedo downloads grandes, será necessário desativar o reúso com Transport.DisableKeepAlives
  • Servidores HTTP/2 passam a entender prioridades de cliente da RFC 9218 e processam primeiro streams de maior prioridade
    • É possível restaurar o comportamento anterior round-robin com Server.DisableClientPriority = true
  • crypto/x509.SystemCertPool no Windows e no macOS passa a oferecer suporte a SSL_CERT_FILE e SSL_CERT_DIR
    • Quando essas variáveis estão definidas, certificados raiz do disco são lidos e o verificador do Go é usado no lugar da API da plataforma
    • Isso pode ser desativado com GODEBUG=x509sslcertoverrideplatform=0
  • A implementação de HTTP/2, antes incluída no arquivo gerado de 12.226 linhas h2_bundle.go, foi substituída por um pacote real net/http/internal/http2
  • Foram adicionados ao net/http hooks de HTTP/3 plugáveis ainda pré-públicos, e parte da suíte de testes já roda sobre HTTP/3
    • Ainda não existe API pública utilizável, mas a base para um futuro http.Transport sobre QUIC já está incluída

Toolchain

  • go test passa a executar por padrão a verificação de vet stdversion, que procura uso de símbolos da biblioteca padrão mais novos que a versão de Go declarada em go.mod
  • go doc pkg@version permite consultar a documentação de uma versão específica de módulo
  • go doc -ex lista exemplos executáveis, e ao indicar diretamente o nome do exemplo exibe seu código-fonte
  • go fix ganha os analisadores de modernização atomictypes, embedlit, slicesbackward e unsafefuncs
    • waitgroup foi renomeado para waitgroupgo e fmtappendf foi removido
  • Em módulos Go 1.27+, go mod tidy consolida blocos require dispersos em dois blocos, um para dependências diretas e outro para indiretas, preservando comentários
  • go tool trace -http=:6060 passa a bindar apenas em localhost quando apenas a porta é informada; para acesso externo, é preciso especificar o endereço
  • O comando go remove o suporte ao sistema de controle de versão Bazaar (bzr)
  • compile, link, asm, cgo, cover e pack passam a oferecer suporte a arquivos de resposta (@file) no formato GCC para evitar limites de tamanho de linha de comando

Unicode e fronteiras de segurança

  • Os dados Unicode da biblioteca padrão foram atualizados de Unicode 15 para Unicode 17
    • Caracteres adicionados no Unicode 16 também passam a ser classificados corretamente como símbolos ou caracteres imprimíveis
  • Foi corrigido um problema que permitia escapar para fora da raiz usando os.Root.ReadDir e Readdir
  • O uso não autorizado de //go:linkname ficou mais difícil
    • A diretiva linknamestd marca linknames que só a biblioteca padrão pode importar
    • Como o linker também passa a verificar acesso por linkname a símbolos de assembly, código que depende de símbolos internos não oficiais precisa ser testado antecipadamente

1 comentários

 
GN⁺ 2 시간 전
Comentários no Lobste.rs
  • Talvez seja o melhor release de todos os tempos. SIMD, uuid, jsonv2 finalmente chegaram

    • Também precisaria ter suporte a UUID v5 para dar uma migração completa
  • Fugindo um pouco do tema, este é um bom exemplo de como surgem bugs quando tudo é tratado como string e não se considera os contratos e as relações entre métodos de interface
    Equal ignora maiúsculas e minúsculas, mas Hash usa o valor convertido para minúsculas. Porém, EqualFold e ToLower não definem a mesma relação de equivalência
    https://github.com/golang/go/issues/52204
    "\u017F" (ſ, s longo) e "s" são iguais em EqualFold, mas o resultado de ToLower para cada um é diferente. Assim, se você inserir "s" e depois "ſ", os hashes serão diferentes e isso fará com que sejam inseridos como itens separados
    O mais curioso é que a documentação alerta exatamente sobre esse caso
    https://github.com/golang/go/…

  • Bom ver outra pessoa continuando de onde Anton parou

    • Infelizmente, pelo menos algumas partes, especialmente a de uso básico do JSON v2, parecem ter sido escritas por LLM. Não gosto do estilo, mas o conteúdo ainda é interessante
    • Parece que Anton não parou de fato. Ele também escreveu a 1.26, então este texto parece apenas ter sido publicado primeiro por outra pessoa
  • Gosto de Go, mas fico em dúvida se a sintaxe de Go é elegante o bastante para continuar acrescentando esse tipo de recurso a cada release
    func (b Box[T]) Map[U any](f func(T) U) Box[U] {

    • É subjetivo, mas não acho pior do que em outras linguagens que suportam isso. Zig é a mais parecida, e Rust, TypeScript e C++20 em geral usam o tipo como contêiner da definição do método para reduzir o custo de repetir o tipo do receiver em vários métodos
      Já a verbosidade de Go e Zig tem a vantagem de não obrigar você a rolar para outro lugar para encontrar a definição do receiver. No ponto de chamada, que dá para considerar mais importante do que a própria definição, todas acabam parecendo quase iguais e nem exigem explicitar o tipo
  • Faz tempo que eu estava longe de Go, e jsonv2 parece promissor. Mas, se virar o padrão, fico me perguntando se isso não quebraria a promessa de compatibilidade que Go mantém há tanto tempo

    • jsonv2 precisa ser importado de um caminho separado, encoding/json/v2, então é algo que você escolhe explicitamente. O encoding/json existente usa v2 internamente, mas preserva o comportamento anterior, e o jsonv2 também traz flags para reproduzir os comportamentos excepcionais da v1, então isso não quebra a promessa de compatibilidade
    • Estou usando a biblioteca jsontext da v2 em um projeto Go 1.26 e estou bem satisfeito com ela