Os documentos de introdução dedicam muitos parágrafos para explicar a diferença entre new()
e make()
, mas na prática, você pode criar objetos no escopo local e devolvê-los.
Por que você usaria o par de alocadores?
Coisas que você pode fazer e make
que não pode fazer de outra maneira:
É um pouco mais difícil de justificar new
. A principal coisa que facilita é criar ponteiros para tipos não compostos. As duas funções abaixo são equivalentes. Um é apenas um pouco mais conciso:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
m := map[string]int{}
vez dem := make(map[string]int)
? não é necessário pré-alocar o tamanho também.O Go possui várias maneiras de alocação de memória e inicialização de valor:
&T{...}
,&someLocalVar
,new
,make
A alocação também pode ocorrer ao criar literais compostos.
new
pode ser usado para alocar valores como números inteiros,&int
é ilegal:A diferença entre
new
emake
pode ser vista observando o seguinte exemplo:Suponha que o Go não tenha
new
emake
, mas tenha a função internaNEW
. Em seguida, o código de exemplo ficaria assim:O
*
seria obrigatório , então:Sim, fundindo
new
emake
em uma única função built-in é possível. No entanto, é provável que uma única função interna leve a mais confusão entre os novos programadores Go do que ter duas funções internas.Considerando todos os pontos acima, parece mais apropriado
new
emake
permanecer separado.fonte
int
é criado.make(Point)
emake(int)
nessas duas últimas linhas?make
A função aloca e inicializa um objeto do tipo fatia, mapa ou chan apenas. Comonew
, o primeiro argumento é um tipo. Mas, também pode levar um segundo argumento, o tamanho. Diferente do novo, o tipo de retorno do make é o mesmo que o tipo de argumento, não um ponteiro para ele. E o valor alocado é inicializado (não definido como valor zero como no novo). A razão é que fatia, mapa e chan são estruturas de dados. Eles precisam ser inicializados, caso contrário, não serão utilizáveis. Esta é a razão pela qual new () e make () precisam ser diferentes.Os exemplos a seguir do Effective Go deixam muito claro:
fonte
new([]int)
, ele apenas aloca memória para [] int, mas não inicializa, apenas retornanil
; não o ponteiro para a memória porque é inutilizável.make([]int)
aloca e inicializa para que seja utilizável; em seguida, retorne seu endereço.new(T)
- Aloca memória e define o valor zero para o tipo T ... queé
0
para int ,""
para string enil
para tipos referenciados ( fatia , mapa , chan )Observe que os tipos referenciados são apenas ponteiros para algumas estruturas de dados subjacentes , que não serão criadas pelo
new(T)
Exemplo: no caso de fatia , a matriz subjacente não será criada,
new([]int)
retornando assim um ponteiro a nadamake(T)
- Aloca memória para tipos de dados referenciados ( fatia , mapa , chan ), além de inicializar suas estruturas de dados subjacentesExemplo: no caso de fatia , a matriz subjacente será criada com o comprimento e a capacidade especificados.
Lembre-se de que, diferentemente de C, uma matriz é um tipo primitivo no Go!
Dito isto:
make(T)
comporta-se como sintaxe literal compostanew(T)
se comporta comovar
(quando a variável não é inicializada)Execute o programa
Leitura adicional:
https://golang.org/doc/effective_go.html#allocation_new https://golang.org/doc/effective_go.html#allocation_make
fonte
Você precisa
make()
criar canais e mapas (e fatias, mas eles também podem ser criados a partir de matrizes). Não há maneira alternativa de fazer isso, então você não pode removermake()
do seu léxico.Quanto a
new()
, não conheço nenhuma razão imediata por que você precisa quando pode usar a sintaxe struct. Porém, ele possui um significado semântico exclusivo, que é "criar e retornar uma estrutura com todos os campos inicializados com seu valor zero", o que pode ser útil.fonte
Além de tudo explicado no Effective Go , a principal diferença entre
new(T)
e&T{}
é que o último executa explicitamente uma alocação de heap. No entanto, deve-se notar que isso depende da implementação e, portanto, pode estar sujeito a alterações.Comparando
make
comnew
faz pouco sentido, pois os dois desempenham funções totalmente diferentes. Mas isso é explicado em detalhes no artigo vinculado.fonte
&T{}
executa explicitamente uma alocação de heap é AFAIK, não baseada em nada nas especificações. Na verdade, acredito que a análise de escape já esteja mantendo esse * T na pilha sempre que possível, exatamente da mesma maneira que comnew(T)
.novo (T): retorna um ponteiro para digitar T um valor do tipo * T, aloca e zera a memória. new (T) é equivalente a & T {} .
make (T): retorna um valor inicializado do tipo T , aloca e inicializa a memória. É usado para fatias, mapa e canais.
fonte