纯函数,其中一个参数是切片

huangapple go评论88阅读模式
英文:

Pure function with a slice as a parameter

问题

如果我需要在go中传递一个(小)切片作为参数,最好的方法是什么?
切片不像数组一样按值传递。因此,在函数执行期间无法保证它不会被修改。
一种解决方案是每次调用函数时都复制切片。这在实践中可以工作,但我更喜欢一种更安全的解决方案,因为无法确保在函数调用之前将会进行复制。

英文:

What is the best way to write a pure function in go if I need to pass a (small) slice in parameter?
Slice are not passed by value like array. So it's not possible to guarantee that it will not be modified during the execution of the function.
Once solution is to copy the slice every time I call the function. It would work in practice, but I would prefer a more safe solution as there is no way to ensure that a copy will ever be made before the function call.

答案1

得分: 2

你是对的,由于切片是引用值,所以不可能有一个真正纯粹的函数带有切片参数。

根据你的需求,你可以使用数组。数组有固定数量的元素,并且声明如下:

var myArray [10]int

当通过值传递时,数组会被复制。

另一种可能性是将切片封装在一个只允许从切片中读取而不允许写入的接口中。

这里有一个例子

package main

import "fmt"

// 接口
type ReadOnlyStringSlice interface {
    Get(int) string
}

// ReadOnlyStringSlice的实现
type MyReadOnlySlice struct {
    slice []string
}

func (m MyReadOnlySlice) Get(i int) string {
    e := m.slice[i]
    return e
}

// 你的“纯粹”函数
func MyPureFunction(r ReadOnlyStringSlice) {
    fmt.Println(r.Get(0))
}

func main() {
    m := MyReadOnlySlice{[]string{"foo", "bar"}}
    MyPureFunction(m)
}
英文:

You are right that since slices are reference values, a truly pure function with a slice argument is not possible.

Depending on your needs, you could use an array. An array has a fixed number of elements and is declared as follows:

var myArray [10]int

Arrays are copied when passed by value.

Another possibility would be to encapsulate the slice in an interface that only allows to read from the slice, not to write to it.

Here's an example:

package main

import "fmt"

// The interface
type ReadOnlyStringSlice interface {
	Get(int) string
}

// An implementation of ReadOnlyStringSlice
type MyReadOnlySlice struct {
	slice []string
}

func (m MyReadOnlySlice) Get(i int) string {
	e := m.slice[i]
	return e
}

// Your "pure" function
func MyPureFunction(r ReadOnlyStringSlice) {
	fmt.Println(r.Get(0))
}

func main() {
	m := MyReadOnlySlice{[]string{"foo", "bar"}}
	MyPureFunction(m)
}

答案2

得分: 2

不是一个真正的答案,但还是值得讨论的,我想。

我认为整个想法是一厢情愿的:在一个不以任何方式使用函数纯净性的语言中,努力实现一个纯函数是没有意义的。如果你能够“标记”一个函数为纯函数,Go 理论上可以利用这个提示来优化执行一系列函数调用的顺序。但由于没有明确支持这种类型的功能,函数的纯净性只存在于你的思想中。例如,假设你能够强制一个函数不修改传递给它的切片;即使如此,你仍然可以在该函数中执行另一个副作用(比如进行 I/O 操作或修改全局变量)。

如果你正在编写一个库,并希望调用者提供一个回调函数,该回调函数不得更改传递给它的切片,请在文档中明确说明这一点。

英文:

Not a real answer, but still worth discussing I suppose.

I think the whole idea is wishful thinking: there's no point in striving to have a pure function in a language which does not in any way use the fact your function is pure. If you could "mark" a function as being pure, Go would in theory be able to somehow use this hint to its advantage (for instance, to reorder execution of some functions in a sequence of calls). Since there's no explicit support for such kind of thing, the function's purity only exists in your mind. For instance, suppose you were able to somehow force a function not to modify a slice passed to it; even then nothing would prevent you from performing another side effect in that function (say, doing I/O or modifying a global variable).

If you're writing a library and want its caller to supply a callback taking a slice which the callback must not change, just state this fact clearly in the documentation.

答案3

得分: 0

如果你正在编写一个包,你可以导出一个方法,该方法接受一个切片,但会复制它并将其传递给真正的函数:

func MyExportedFunc(someSlice []int) {
    sliceCopy := make([]int, len(someSlice))
    copy(sliceCopy, someSlice)

    myUnexportedFunc(sliceCopy)
}

当然,这并不是一个通用问题的解决方案,因为MyExportedFunc不是纯函数。最好的方法可能是像@Tom建议的那样封装切片。

英文:

If you're writing a package, you could export a method which takes a slice but copies
it and passes it to the real function:

func MyExportedFunc(someSlice []int) {
    sliceCopy := make([]int, len(someSlice))
    copy(sliceCopy, someSlice)

    myUnexportedFunc(sliceCopy)
}

This, of course, is not a solution for the problem in general, as MyExportedFunc is not
pure. The best way is probably to encapsulate the slice, as @Tom suggested.

huangapple
  • 本文由 发表于 2012年12月11日 05:33:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/13809624.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定