Использование указателя на массив - PullRequest
31 голосов
/ 13 марта 2010

Я немного поиграюсь с языком Go Google, и столкнулся с чем-то довольно простым в C, но, похоже, не описанным в документации, которую я видел до сих пор

Когда я передаю указатель на фрагмент функции, я предполагал, что у нас будет какой-то способ получить к нему доступ следующим образом:

func conv(x []int, xlen int, h []int, hlen int, y *[]int)

    for i := 0; i<xlen; i++ {
        for j := 0; j<hlen; j++ {
            *y[i+j] += x[i]*h[j]
        }
    }
 }

Но компилятору Go это не нравится:

sean@spray:~/dev$ 8g broke.go
broke.go:8: invalid operation: y[i + j] (index of type *[]int)

Достаточно справедливо - это было только предположение. У меня довольно простой обходной путь:

func conv(x []int, xlen int, h []int, hlen int, y_ *[]int) {
    y := *y_

    for i := 0; i<xlen; i++ {
        for j := 0; j<hlen; j++ {
            y[i+j] += x[i]*h[j]
        }
    }
}

Но, несомненно, есть лучший способ. Раздражает то, что поиск информации о Go не очень полезен, поскольку для большинства поисковых терминов появляются всевозможные результаты, связанные с C / C ++ /.

Ответы [ 5 ]

25 голосов
/ 14 марта 2010

В документах Google Go указано следующее о передаче массивов - они говорят, что вы обычно хотите передать фрагмент (вместо указателя?):

Обновлен:

Как указано в комментарии @ Chickencha, срезы массивов являются ссылками, поэтому они эффективны для передачи. Поэтому, вероятно, вы захотите использовать механизм слайсов вместо «сырых» указателей.

С Google Effective Go Doc http://golang.org/doc/effective_go.html#slices

Ломтики являются справочными типами,


Оригинал

Это под заголовком

Интерлюдия о типах

[... snip ...] При передаче массива к функции, вы почти всегда хотите объявить формальный параметр ломтик. Когда вы вызываете функцию, взять адрес массива и перейти создаст (эффективно) срез ссылка и передать это.

Примечание редактора: это уже не так

Используя слайсы, можно написать эту функцию (из sum.go):

09    func sum(a []int) int {   // returns an int
10        s := 0
11        for i := 0; i < len(a); i++ {
12            s += a[i]
13        }
14        return s
15    }

и вызвать его так:

19        s := sum(&[3]int{1,2,3})  // a slice of the array is passed to sum    

Может быть, вместо этого передать весь массив в виде среза. Google указывает, что Go эффективно работает с ломтиками. Это альтернативный ответ на вопрос, но, возможно, это лучший способ.

14 голосов
/ 31 марта 2010

Типы с пустыми [], такие как []int, на самом деле являются слайсами, а не массивами. В Go размер массива является частью типа, поэтому для того, чтобы иметь массив, вам нужно иметь что-то вроде [16]int, а указатель на него будет *[16]int. Итак, то, что вы на самом деле уже делаете, - это использование слайсов, и указатель на слайс, *[]int, не нужен, так как слайсы уже передаются по ссылке.

Также помните, что вы можете легко передать фрагмент, ссылающийся на весь массив, с помощью &array (при условии, что тип элемента фрагмента совпадает с типом элемента массива). (Больше нет.)

Пример:

package main
import "fmt"

func sumPointerToArray(a *[8]int) (sum int) {
    for _, value := range *a { sum += value }
    return
}
func sumSlice (a []int) (sum int) {
    for _, value := range a { sum += value }
    return
}
func main() {
    array := [...]int{ 1, 2, 3, 4, 5, 6, 7, 8 }
    slice := []int{ 1, 2, 3, 4 }
    fmt.Printf("sum arrray via pointer: %d\n", sumPointerToArray(&array))
    fmt.Printf("sum slice: %d\n", sumSlice(slice))
    slice = array[0:]
    fmt.Printf("sum array as slice: %d\n", sumSlice(slice))
}

Редактировать : Обновлено, чтобы отразить изменения в Go с тех пор, как это было впервые опубликовано.

5 голосов
/ 13 марта 2010

точка с запятой и звездочка добавляются и удаляются.

* y [i + j] + = x [i] * h [j]
->
(* y) [i + j] + = x [i] * h [j];

2 голосов
/ 15 марта 2010

Вот рабочая программа Go.

package main

import "fmt"

func conv(x, h []int) []int {
    y := make([]int, len(x)+len(h)-1)
    for i := 0; i < len(x); i++ {
        for j := 0; j < len(h); j++ {
            y[i+j] += x[i] * h[j]
        }
    }
    return y
}

func main() {
    x := []int{1, 2}
    h := []int{7, 8, 9}
    y := conv(x, h)
    fmt.Println(len(y), y)
}

Чтобы избежать неправильных догадок, прочтите документацию Go: Язык программирования Go.

2 голосов
/ 15 марта 2010

Длина является частью типа массива, вы можете получить длину массива с помощью встроенной функции len (). Так что вам не нужно передавать аргументы xlen, hlen.

В Go вы почти всегда можете использовать слайс при передаче массива в функцию. В этом случае вам не нужны указатели. На самом деле, вам не нужно передавать аргумент y. Это способ вывода массива C.

В стиле Go:

func conv(x, h []int) []int {
    y := make([]int, len(x)+len(h))
    for i, v := range x { 
        for j, u := range h { 
            y[i+j] = v * u 
        }   
    }   
    return y
}

Вызовите функцию:

conv(x[0:], h[0:])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...