Supongamos que tengo estos tipos:
type Attribute struct {
Key, Val string
}
type Node struct {
Attr []Attribute
}
y que quiero iterar sobre los atributos de mi nodo para cambiarlos.
Me hubiera encantado poder hacer:
for _, attr := range n.Attr {
if attr.Key == "href" {
attr.Val = "something"
}
}
pero como attr
no es un puntero, esto no funcionaría y tengo que hacer:
for i, attr := range n.Attr {
if attr.Key == "href" {
n.Attr[i].Val = "something"
}
}
¿Hay una manera más simple o más rápida? ¿Es posible obtener directamente punteros range
?
Obviamente no quiero cambiar las estructuras solo por la iteración y las soluciones más detalladas no son soluciones.
Array.prototype.forEach
JavaScript?forEach
necesariamente comenzaría con una aserción de tipo. Eso no es realmente mejor queattr := &n.Attr[i]
.Respuestas:
No, la abreviatura que desea no es posible.
La razón de esto es que
range
copia los valores del segmento sobre el que está iterando. La especificación sobre el rango dice:Por lo tanto, el rango utiliza
a[i]
como su segundo valor para matrices / sectores, lo que significa que el valor se copia, haciendo que el valor original sea intocable.Este comportamiento se demuestra mediante el siguiente código :
El código le imprime ubicaciones de memoria completamente diferentes para el valor del rango y el valor real en el segmento:
Entonces, lo único que puede hacer es usar punteros o el índice, como ya lo propusieron jnml y peterSO.
fuente
a[i]
el for loop y ela[i]
mientras escribimos? Parece lo mismo pero no lo es, ¿verdad?range
regresaa[i]
como su segundo valor de retorno. Esta operación,val = a[i]
como se hace mediante,range
crea una copia del valor, de modo que cualquier operación de escrituraval
se aplica a una copia.Parece que estás pidiendo algo equivalente a esto:
Salida:
Esto evita crear una copia, posiblemente grande, de los
Attribute
valores de tipo , a expensas de las comprobaciones de los límites de corte. En su ejemplo, el tipoAttribute
es relativamente pequeño, dosstring
referencias de segmento: 2 * 3 * 8 = 48 bytes en una máquina de arquitectura de 64 bits.También podrías simplemente escribir:
Pero, la forma de obtener un resultado equivalente con una
range
cláusula, que crea una copia pero minimiza las comprobaciones de los límites de corte, es:fuente
value := &someMap[key]
no funcione sisomeMap
es unmap
*attr.Val = "something"
Adaptaría su última sugerencia y usaría la versión de rango de solo índice.
Me parece más simple referirme
n.Attr[i]
explícitamente tanto en la línea que pruebaKey
como en la línea que estableceVal
, en lugar de usarattr
para una yn.Attr[i]
para la otra.fuente
Por ejemplo:
Patio de recreo
Salida
Enfoque alternativo:
Patio de recreo
Salida:
fuente
go.net/html
paquete)