英文:
Go: Call a function passing pointer to array
问题
我花了一些时间尝试做这个,我认为我需要一个全局数组(而不是切片),并且我想通过指针传递它,而不是通过值。接收指针的函数需要测试是否为nil,如果为nil,则使用例如“baForm, oOserr = ioutil.ReadFile(sFormName)”从磁盘读取数组。调用函数可以传递全局数组或调用函数本地的数组,我假设后者将被垃圾回收。
这样做的原因是我想要一个标准函数从磁盘读取表单,经常使用的表单存储在全局。尽管有些人可能认为有更好的方法,但我仍然想知道如何实现这一点,即:a)有全局或本地数组,b)不通过值传递,c)全局数组将从磁盘只读取一次,而本地数组将在每次调用函数时读取。谢谢。
英文:
I have spent a bit of time attempting to do this, and I think I need a global array (not slice), and I want to pass it as a pointer, not by value. The function receiving the pointer needs to test for nil, and if nil, read the array from disk, using eg: "baForm, oOserr = ioutil.ReadFile(sFormName)". The calling function may pass either a global array or an array local to the calling function which I presume will be garbage collected.
The reason for doing this is that I want a standard function to read the forms from disk, and often-used forms are stored globally. Despite whether some may think there is a better way, I still want to know how to achieve this ie: a) have global or local array, b) not pass by value, c) The global arrays will be read only once from disk and the local arrays will be read each time the function is called. TIA.
答案1
得分: 1
从你的描述中,我看不出为什么传递一个指向数组的指针比传递一个切片更好 - 但这取决于你。
你可以像在C语言中一样传递一个指针 - 在声明中加上一个星号(*
),在调用函数时在值前加上一个和号(&
)。
只要记住,在Go语言中,数组的大小是其类型的一部分。这意味着你的函数声明将嵌入数组的大小,所以你不能使用不同大小的数组调用该函数。仅仅因为这个原因,通常就足以使用切片而不是数组。
英文:
From reading your description, I can't see why passing a pointer to an array is any way better than passing a slice -- but it's up to you.
You can pass a pointer just like you do in C -- attach an asterisk (*
) to the declaration, and perpend an ampersand (&
) to the value when you call the function.
Just remember that in Go, the array size is part of its type. This means that your function declaration will have the array size embedded into it, so you can't call the function using an array of any different size. This reason alone is generally enough to warrant using a slice instead of an array.
答案2
得分: 0
这是一个示例程序,它基于使用计数来维护一个动态表单缓冲区。如果ReadForm函数找到一个表单,它会返回表单的地址和一个空错误。
package main
import (
"fmt"
"io/ioutil"
"math"
"os"
"sync"
)
type Form struct {
Name string
useCount int64
Data []byte
}
// 表单缓冲区的容量。
const formsCap = 2
// 表单缓冲区。
var (
forms = make(map[string]*Form, formsCap)
formsLock sync.RWMutex
)
func ReadForm(name string) (form *Form, err os.Error) {
formsLock.RLock()
form, ok := forms[name]
formsLock.RUnlock()
if !ok {
form = &Form{name, 0, nil}
}
if form.Data == nil {
data, err := ioutil.ReadFile(name + ".form")
if err != nil {
return nil, err
}
form = &Form{name, 0, data}
formsLock.Lock()
if len(forms) >= formsCap {
minForm := &Form{useCount: math.MaxInt64}
for i, f := range forms {
if f.useCount < minForm.useCount {
minForm = f
}
}
minform.Data = nil
}
forms[name] = form
formsLock.Unlock()
}
form.useCount++
return form, nil
}
func main() {
// 表单文件的命名为name.form,例如form1.form
for _, name := range []string{"form1", "form2", "form3"} {
f, err := ReadForm(name)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(f.Data))
}
}
fmt.Println(len(forms), forms)
}
编辑:映射操作不是原子操作。 修改示例程序,使用互斥锁来并发访问forms
映射。
英文:
Here's a sample program that maintains a dynamic forms buffer based on use count. If the ReadForm function finds a form, it returns the address of the form and a nil error.
package main
import (
"fmt"
"io/ioutil"
"math"
"os"
"sync"
)
type Form struct {
Name string
useCount int64
Data []byte
}
// The capacity of the forms buffer.
const formsCap = 2
// The forms buffer.
var (
forms = make(map[string]*Form, formsCap)
formsLock sync.RWMutex
)
func ReadForm(name string) (form *Form, err os.Error) {
formsLock.RLock()
form, ok := forms[name]
formsLock.RUnlock()
if !ok {
form = &Form{name, 0, nil}
}
if form.Data == nil {
data, err := ioutil.ReadFile(name + ".form")
if err != nil {
return nil, err
}
form = &Form{name, 0, data}
formsLock.Lock()
if len(forms) >= formsCap {
minForm := &Form{useCount: math.MaxInt64}
for i, f := range forms {
if f.useCount < minForm.useCount {
minForm = f
}
}
minform.Data = nil
}
forms[name] = form
formsLock.Unlock()
}
form.useCount++
return form, nil
}
func main() {
// form files are named name.form e.g. form1.form
for _, name := range []string{"form1", "form2", "form3"} {
f, err := ReadForm(name)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(f.Data))
}
}
fmt.Println(len(forms), forms)
}
EDIT: Map operations are not atomic. Revise the sample program to use a mutex for concurrent access to the forms
map.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论