调用通用函数类型:无效操作:无法调用非函数 fn。

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

Calling a generic function type: invalid operation: cannot call non-function fn

问题

我将发布我目前正在处理的代码示例。我遇到了错误:

error: invalid operation: cannot call non-function fn (variable of type MF constrained by MapFunc)

是否可以使用包含不同函数签名的约束以这种方式使用?(如果可能的话,我想先了解如何使我编写的代码正常工作。)

以下是示例代码:

package main

import "fmt"

// MapFunc constraint used in Funcy
type MapFunc interface {
	func(s string, ss []string) []string | func(s string, ss []string) []bool
}

// MapFuncType used for Funcy return constraint
type MapFuncType interface {
	string | bool
}

// Funcy preforms map operation on generic map functions
func Funcy[MF MapFunc, MFT MapFuncType](s string, ss []string, fn MF) []MFT {
	return fn(s, ss)
	// error: invalid operation: cannot call non-function fn (variable of type
	// MF constrained by MapFunc)
}

// appendTo adds given string to the end of each index of given slice of strings
// Ex. appendTo("_", []string{"append", "to"}) --> []string{"append_", "to_"}
func appendTo(s string, ss []string) []string {
	var slice []string
	for _, v := range ss {
		slice = append(slice, v+s)
	}
	return slice
}

// isMatch checks given string against each index in given string slice for a
// match
// Ex. isMatch("hi", []string{"hello", "hi"}) --> []bool{false, true}
func isMatch(s string, ss []string) []bool {
	var slice []bool
	for _, v := range ss {
		slice = append(slice, s == v)
	}
	return slice
}

func main() {
	slice1 := []string{"append", "to"}
	slice2 := []string{"hello", "hi"}

	fmt.Println(Funcy(slice1, appendTo))
	// want: []string{"append_", "to_"}
	// got: error: cannot infer MFT

	fmt.Println(Funcy(slice2, isMatch))
	//[]bool{false, true}
	// got: error: cannot infer MFT
}
英文:

I'll post the code example that I am currently working on. I got the error:

> error: invalid operation: cannot call non-function fn (variable of type MF constrained by MapFunc)

Is it possible to use constraints that contain different function signatures to be used in this way? (I would like to understand how to get what I have written to work first if at all possible.)

Here is the example:

package main
import "fmt"
// MapFunc constraint used in Funcy
type MapFunc interface {
func(s string, ss []string) []string | func(s string, ss []string) []bool
}
// MapFuncType used for Funcy return constraint
type MapFuncType interface {
string | bool
}
// Funcy preforms map operation on generic map functions
func Funcy[MF MapFunc, MFT MapFuncType](s string, ss []string, fn MF) []MFT {
return fn(s, ss)
// error: invalid operation: cannot call non-function fn (variable of type
// MF constrained by MapFunc)
}
// appendTo adds given string to the end of each index of given slice of strings
// Ex. appendTo("_", []string{"append", "to"}) --> []string{"append_", "to_"}
func appendTo(s string, ss []string) []string {
var slice []string
for _, v := range ss {
slice = append(slice, v+s)
}
return slice
}
// isMatch checks given string against each index in given string slice for a
// match
// Ex. isMatch("hi", []string{"hello", "hi"}) --> []bool{false, true}
func isMatch(s string, ss []string) []bool {
var slice []bool
for _, v := range ss {
slice = append(slice, s == v)
}
return slice
}
func main() {
slice1 := []string{"append", "to"}
slice2 := []string{"hello", "hi"}
fmt.Println(Funcy(slice1, appendTo))
// want: []string{"append_", "to_"}
// got: error: cannot infer MFT
fmt.Println(Funcy(slice2, isMatch))
//[]bool{false, true}
// got: error: cannot infer MFT
}

答案1

得分: 2

当你将类型参数MF约束为MapFunc时,你无法调用fn,因为MapFunc类型集中的函数类型没有相同的签名。它们具有不同的返回类型[]string[]bool

因此,类型为fn的变量实际上不支持调用,你会得到一个(稍微晦涩的)错误消息"cannot call non-function fn"。

更正式地说,只有具有核心类型为函数类型的值才能被调用,但约束MapFunc没有核心类型。

修复的方法是将MapFunc参数化,并将该类型参数用作返回值,这样在实例化时,它将具有核心类型:

type MapFunc[T MapFuncType] interface {
	func(s string, ss []string) []T
}

并在Funcy中使用MFT实例化约束:

func Funcy[MF MapFunc[MFT], MFT MapFuncType](s string, ss []string, fn MF) []MFT {
	return fn(s, ss)
}

Playground: https://go.dev/play/p/q88aJLgnzXZ

英文:

When you constrain the type param MF to MapFunc, you can't call fn because the function types in MapFunc's type set don't have the same signature. They have different return types []string and []bool.

So the variable of type fn effectively does not support being called, and you get the (slightly cryptic) error message "cannot call non-function fn".

More formally, only a value that has a core type of type function can be called, but the constraint MapFunc doesn't have a core type.

The fix would be to parametrize MapFunc and use that type parameter as the return value, so that upon instantiation, it would have a core type:

type MapFunc[T MapFuncType] interface {
func(s string, ss []string) []T
}

And instantiate the constraint with MFT in Funcy:

func Funcy[MF MapFunc[MFT], MFT MapFuncType](s string, ss []string, fn MF) []MFT {
return fn(s, ss)
}

Playground: https://go.dev/play/p/q88aJLgnzXZ

huangapple
  • 本文由 发表于 2022年3月19日 23:38:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/71539554.html
匿名

发表评论

匿名网友

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

确定