Il n'y a pas de manière plus concise, ce que vous avez fait est la «bonne» manière; parce que les tranches sont toujours unidimensionnelles mais peuvent être composées pour construire des objets de dimension supérieure. Voir cette question pour plus de détails: Aller: Comment est la représentation mémoire d'un tableau à deux dimensions .
Une chose que vous pouvez simplifier est d'utiliser la for range
construction:
a := make([][]uint8, dy)
for i := range a {
a[i] = make([]uint8, dx)
}
Notez également que si vous initialisez votre tranche avec un littéral composite , vous obtenez ceci gratuitement, par exemple:
a := [][]uint8{
{0, 1, 2, 3},
{4, 5, 6, 7},
}
fmt.Println(a) // Output is [[0 1 2 3] [4 5 6 7]]
Oui, cela a ses limites car apparemment, vous devez énumérer tous les éléments; mais il y a quelques astuces, à savoir que vous n'avez pas à énumérer toutes les valeurs, seulement celles qui ne sont pas les valeurs nulles du type d'élément de la tranche. Pour plus de détails à ce sujet, consultez Éléments clés dans l'initialisation du tableau golang .
Par exemple, si vous voulez une tranche où les 10 premiers éléments sont des zéros, puis suit 1
et 2
, elle peut être créée comme ceci:
b := []uint{10: 1, 2}
fmt.Println(b) // Prints [0 0 0 0 0 0 0 0 0 0 1 2]
Notez également que si vous utilisez des tableaux au lieu de tranches , il peut être créé très facilement:
c := [5][5]uint8{}
fmt.Println(c)
La sortie est:
[[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
Dans le cas de tableaux, vous n'avez pas à parcourir le tableau «externe» et à initialiser les tableaux «internes», car les tableaux ne sont pas des descripteurs mais des valeurs. Voir le billet de blog Tableaux, tranches (et chaînes): les mécanismes de 'append' pour plus de détails.
Essayez les exemples sur le Go Playground .
cannot use [5][2]string literal (type [5][2]string) as type [][]string in field value
quand j'essaye d'assigner le tableau à ce que je suppose que je dis que Go est une tranche.Il existe deux façons d'utiliser des tranches pour créer une matrice. Jetons un coup d'œil aux différences entre eux.
Première méthode:
Deuxième méthode:
En ce qui concerne la première méthode, faire des
make
appels successifs ne garantit pas que vous vous retrouverez avec une matrice contiguë, donc vous pouvez avoir la matrice divisée en mémoire. Pensons à un exemple avec deux routines Go qui pourraient causer ceci:make([][]int, n)
pour obtenir de la mémoire allouéematrix
, obtenant un morceau de mémoire de 0x000 à 0x07F.make([]int, m)
, passant de 0x080 à 0x0FF.make
(à ses propres fins) et obtient de 0x100 à 0x17F (juste à côté de la première ligne de la routine # 0).make([]int, m)
correspondance avec la deuxième itération de boucle et obtient de 0x180 à 0x1FF pour la deuxième ligne. À ce stade, nous avons déjà deux lignes divisées.Avec la deuxième méthode, la routine fait
make([]int, n*m)
pour obtenir toute la matrice allouée dans une seule tranche, assurant la contiguïté. Après cela, une boucle est nécessaire pour mettre à jour les pointeurs de matrice vers les sous-tranches correspondant à chaque ligne.Vous pouvez jouer avec le code ci-dessus dans le Go Playground pour voir la différence dans la mémoire attribuée en utilisant les deux méthodes. Notez que je l'ai utilisé
runtime.Gosched()
uniquement dans le but de céder le processeur et de forcer le planificateur à passer à une autre routine.Lequel utiliser? Imaginez le pire des cas avec la première méthode, c'est-à-dire que chaque ligne n'est pas la suivante en mémoire d'une autre ligne. Ensuite, si votre programme parcourt les éléments de la matrice (pour les lire ou les écrire), il y aura probablement plus d'erreurs de cache (d'où une latence plus élevée) par rapport à la deuxième méthode en raison de la pire localisation des données. D'un autre côté, avec la deuxième méthode, il peut ne pas être possible d'obtenir un seul morceau de mémoire alloué pour la matrice, en raison de la fragmentation de la mémoire (morceaux répartis sur toute la mémoire), même si théoriquement il peut y avoir suffisamment de mémoire libre pour cela. .
Par conséquent, à moins qu'il y ait beaucoup de fragmentation de la mémoire et que la matrice à allouer soit suffisamment grande, vous voudrez toujours utiliser la deuxième méthode pour tirer parti de la localité des données.
la source
Dans les réponses précédentes, nous n'avons pas considéré la situation où la longueur initiale est inconnue. Dans ce cas, vous pouvez utiliser la logique suivante pour créer une matrice
https://play.golang.org/p/pHgggHr4nbB
la source