英文:
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.
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论