Compartilhamento de tecnologia

[Série Go] array, fatia e mapa

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Conecte o anterior e o próximo

Apresentamos if e for em nosso artigo anterior. Vamos praticar como usá-lo.continue Declaração para calcular a soma de números pares dentro de 100. À medida que escrevemos código,continueinstrução nos ajudará a pular certas iterações que não são necessárias, por exemplo, neste exemplo, pularemos todos os números ímpares.

  1. sum := 0
  2. for i := 1; i < 100; i++{
  3. if i & 1 == 0 {
  4. continue
  5. }
  6. sum += i
  7. }
  8. fmt.Println("the sum is",sum)

Comece a aprender

Na programação, muitas vezes precisamos lidar com um conjunto de elementos do mesmo tipo, e esses conjuntos de elementos são representados por estruturas de dados específicas na linguagem Go. Hoje, apresentarei detalhadamente vários tipos de coleção em Go: array, slice e map.

variedade

Primeiro, vamos começar com matrizes. Array é a estrutura de dados mais básica em Go. É uma sequência de comprimento fixo de elementos do mesmo tipo. Depois que um array é declarado, seu comprimento não pode ser alterado. A declaração e inicialização de arrays são muito simples,

Declarar matriz

Ao declarar um array, você precisa especificar o tipo e o comprimento do array. Veja como um array é declarado:

var arrayName [arrayLength]elementType

Por exemplo, declare uma matriz inteira de comprimento 5:

var numbers [5]int
inicializar matriz

Você pode inicializar um array de várias maneiras:

  • Use inicialização literal:
var numbers = [5]int{1, 2, 3, 4, 5}
  • usar:=Breve declaração:
numbers := [5]int{1, 2, 3, 4, 5}
  • Inferir automaticamente o comprimento da matriz:
numbers := [...]int{1, 2, 3, 4, 5}
  • Especifique a inicialização do índice:
numbers := [5]int{0: 1, 4: 5}

Características das matrizes

  • Comprimento fixo: O comprimento da matriz é determinado quando ela é declarada e não pode ser alterado posteriormente.
  • elementos do mesmo tipo: matrizes só podem conter elementos do mesmo tipo.
  • alocação de memória contígua: os elementos do array são alocados de forma contígua na memória, o que torna o acesso aos elementos do array muito eficiente.

Acessar elementos da matriz

Você pode acessar os elementos de um array por índice, começando em 0:

value := numbers[2] // 获取索引为 2 的元素

Matriz transversal

você pode usarforFaça um loop por todos os elementos de um array:

  1. for i, value := range numbers {
  2. fmt.Printf("Index: %d, Value: %dn", i, value)
  3. }

comprimento da matriz

Você pode usar o integradolenFunção para obter o comprimento de um array:

length := len(numbers)

valor zero da matriz

Se uma matriz não for inicializada explicitamente, seus elementos serão automaticamente definidos com o valor zero de seu tipo. Por exemplo, o valor zero de uma matriz inteira é 0:

var numbers [5]int // 所有元素都是 0

Matrizes multidimensionais

A linguagem Go também oferece suporte a arrays multidimensionais. A seguir está um exemplo de declaração e inicialização de um array inteiro 2x3:

  1. var matrix [2][3]int
  2. matrix = [2][3]int{{1, 2, 3}, {4, 5, 6}}

Limitações de matrizes

Como o comprimento do array é fixo, isso pode não ser muito flexível em alguns casos. Se precisar de uma coleção de comprimento variável, você poderá usar fatias.

fatiar

O próximo é o slice, que é um tipo integrado mais flexível que pode ser considerado um array dinâmico. O comprimento da fatia é variável e ela é criada a partir de um array, proporcionando mais comodidade. Veja como declarar e inicializar uma fatia:

  1. s := make([]int, 3) // 创建一个长度为3的整型切片
  2. s[0] = 1 // 切片元素赋值
  3. s[1] = 2
  4. s[2] = 3
  5. s = append(s, 4) // 向切片追加元素

Na linguagem Go, embora arrays e fatias sejam usados ​​para armazenar uma série de elementos do mesmo tipo, eles apresentam diferenças significativas na alocação de memória, na variabilidade de tamanho e no uso. Aqui estão as principais diferenças entre matrizes e fatias:

variabilidade de tamanho

  • variedade : O tamanho de um array é determinado quando ele é declarado e não pode ser alterado posteriormente.O tamanho de um array faz parte do seu tipo, então[3]inte[4]intsão tipos diferentes.
  • fatiar : as fatias são dinâmicas e podem aumentar ou diminuir em tempo de execução.O tamanho de uma fatia não faz parte do seu tipo, então[]intÉ o tipo comum para todas as fatias inteiras.

alocação de memória

  • variedade : Arrays são tipos de valor e quando um array é passado como parâmetro de função, uma cópia de seu valor é passada. Isso significa que as modificações no array dentro da função não afetam o array original.
  • fatiar : Slice é um tipo de referência que contém um ponteiro para a matriz subjacente, o comprimento e a capacidade da fatia. Quando uma fatia é passada como parâmetro de função, uma cópia do ponteiro é passada, portanto, modificações na fatia dentro da função afetarão a fatia original.

inicialização

  • variedade: Ao inicializar um array, seu tamanho deve ser especificado e os valores dos elementos podem ser atribuídos imediatamente.
  • fatiar: Fatias podem ser passadas por literais,makeFunção ou fatia de uma matriz para inicializar, sem tamanho especificado.

Código de amostra

Aqui estão exemplos de inicialização para arrays e fatias:

  1. // 数组
  2. var arr [3]int = [3]int{1, 2, 3}
  3. // 切片
  4. var slice []int = []int{1, 2, 3}
  5. // 或者使用 make 函数
  6. slice := make([]int, 3)

Diferenças funcionais

  • variedade: Como o tamanho é fixo, o tamanho do array é conhecido em tempo de compilação, o que possibilita alocar memória para o array na pilha, e a complexidade de tempo de acesso aos elementos do array é O(1).
  • fatiar: O fatiamento oferece mais flexibilidadeappend A função adiciona elementos ou obtém subfatias por meio de operações de fatiamento.A matriz subjacente da fatia pode ser alocada no heap, e a complexidade de tempo de acesso aos elementos da fatia também é O(1), masappendPode resultar na realocação da matriz subjacente, que normalmente é uma operação O(n).

mapeamento

Finalmente, vamos dar uma olhada no mapeamento. Um mapa é uma matriz associativa em Go que mapeia chaves para valores. As chaves do mapa podem ser de qualquer tipo suportado pelo operador de igualdade, como inteiros, números de ponto flutuante, strings, ponteiros, interfaces (desde que os valores contidos na interface sejam comparáveis), estruturas e arrays. O valor mapeado pode ser de qualquer tipo.

Declaração e inicialização

declarar mapa

A sintaxe para declarar um mapa é a seguinte:

var mapName map[keyType]valueType

Por exemplo, declare um mapa com chaves como strings e valores como inteiros:

var scores map[string]int
Inicializar mapa

Depois de declarar o mapa, você precisa passarmakefunção para inicializá-lo para que possa ser usado:

scores = make(map[string]int)

Alternativamente, você pode usar uma declaração curta e inicializar:

scores := make(map[string]int)

Você também pode usar literais para inicialização no momento da declaração:

  1. scores := map[string]int{
  2. "alice": 90,
  3. "bob": 85,
  4. "charlie": 88,
  5. }

Recursos do mapa

  • exclusividade principal: Em um mapa, cada chave é única. Se você tentar inserir uma chave existente, o valor correspondente à chave será atualizado.
  • transtorno:map não é ordenado e a ordem dos elementos pode ser diferente cada vez que o mapa é iterado.
  • tamanho dinâmico:O tamanho do mapa é dinâmico, você pode adicionar ou remover pares de valores-chave conforme necessário.
  • tipo de referência: Map é um tipo de referência. Quando você passa map para uma função, o que você realmente passa é um ponteiro para a estrutura de dados subjacente.

Mapa de operação

Adicionar elemento
scores["alice"] = 90
Obter elemento
value := scores["alice"]

Se a chave não existir, será retornado um valor zero para esse tipo de valor.

Verifique se a chave existe

Você pode usar o idioma comma -ok para verificar se a chave existe no mapa:

  1. value, exists := scores["alice"]
  2. if exists {
  3. // 键存在
  4. } else {
  5. // 键不存在
  6. }
Excluir elemento

usardeleteA função pode remover um par de valores-chave do mapa:

delete(scores, "alice")

Se a chave não existir,deleteA função não faz nada.

Percorra o mapa

usarforUm loop pode percorrer todos os pares de valores-chave no mapa:

  1. for key, value := range scores {
  2. fmt.Printf("%s: %dn", key, value)
  3. }

valor zero do mapa

O valor zero do mapa énil .umnil Um mapa não possui estrutura de dados subjacente e não pode adicionar elementos.Antes de adicionar elementos ao mapa, você deve usarmakeInicialize-o.

comprimento do mapa

Você pode usar o integradolenFunção para obter o número de pares de valores-chave no mapa:

length := len(scores)

tipo de chave do mapa

As chaves do mapa podem ser de qualquer tipo comparável, como inteiros, números de ponto flutuante, strings, ponteiros, interfaces (desde que os valores contidos na interface sejam comparáveis), estruturas, arrays, etc. Fatias, mapas e funções não podem ser usados ​​como chaves de mapa porque esses tipos não suportam comparações de igualdade.

Fácil de cometer erros

Na linguagem Go, arrays, fatias e mapas são três estruturas de dados comumente usadas, cada uma com características e considerações diferentes. Aqui estão alguns pontos a serem observados ao usá-los:

Variedade

  • Evite usar arrays excessivamente grandes, pois eles ocupam muito espaço de pilha e podem causar estouro de pilha.
  • Matrizes são usadas quando uma coleção de dados de tamanho fixo é necessária.

Fatiar

  • A realocação de memória pode ocorrer quando o fatiamento é expandido. Tente pré-alocar capacidade suficiente para evitar expansão frequente.
  • Evite usar fatias muito grandes, pois podem ocupar muito espaço na pilha.
  • Observe que o valor zero da fatia énil, precisa ser inicializado antes do uso.

mapa

  • O valor zero do mapa énilnilO mapa não pode ser usado para armazenar pares de valores-chave e deve ser inicializado antes do uso.
  • Em um ambiente simultâneo, as operações de leitura e gravação no mapa não são seguras para threads e precisam ser protegidas usando bloqueios mutex ou outros mecanismos de sincronização.
  • usardeleteExcluir uma chave que não existe não gera erro, mas é seguro verificar se a chave existe.