英文:
Dynamic function call from generics depending on type
问题
能否使用泛型根据参数类型调用函数?
我会尽量详细解释我的任务。
例如,我有一个带有两个方法的结构体:
package main
import "reflect"
type Cut interface {
int | int8 | int16 | int32 | int64 | float32 | float64 | string
}
type AudioObj struct {
fileName string
}
func (A AudioObj) CutIfFirstIsString(from string, to float64) {
// Cut audio file: ("00:00:03", 81.0)
}
func (A AudioObj) CutIfSecondIsString(from float64, to string) {
// Cut audio file: (0.3, "01:21:00")
}
这是我的泛型函数:
func CutAudio[S Cut, E Cut](MusicFile AudioObj, start S, end E) {
// 第一个参数是字符串。
if reflect.ValueOf(start).Kind() == reflect.String {
MusicFile.CutIfFirstIsString(start, end)
}
// 第二个参数是字符串。
if reflect.ValueOf(end).Kind() == reflect.String {
MusicFile.CutIfSecondIsString(start, end)
}
}
在这里,我尝试根据函数参数类型来剪切音频文件:
func main() {
audio := AudioObj{fileName: "music.mp3"}
CutAudio(audio, "00:00:03", 81.0)
CutAudio(audio, 0.3, "01:21:00")
}
输出:
./prog.go:24:32: cannot use start (variable of type S constrained by Cut) as type string in argument to MusicFile.CutIfFirstIsString
./prog.go:24:39: cannot use end (variable of type E constrained by Cut) as type float64 in argument to MusicFile.CutIfFirstIsString
./prog.go:29:33: cannot use start (variable of type S constrained by Cut) as type float64 in argument to MusicFile.CutIfSecondIsString
./prog.go:29:40: cannot use end (variable of type E constrained by Cut) as type string in argument to MusicFile.CutIfSecondIsString
PlayGround: https://go.dev/play/p/1jx1-vHXDdn
是否可以将泛型类型转换为我传递给它的类型?
英文:
Is it possible to use generics to call a function depending on the type of parameters?
I will try to explain my task in as much detail as possible.
For example, I have a structure with two methods:
package main
import "reflect"
type Cut interface {
int | int8 | int16 | int32 | int64 | float32 | float64 | string
}
type AudioObj struct {
fileName string
}
func (A AudioObj) CutIfFirstIsString(from string, to float64) {
// Cut audio file: ("00:00:03", 81.0)
}
func (A AudioObj) CutIfSecondIsString(from float64, to string) {
// Cut audio file: (0.3, "01:21:00")
}
And this is my generic:
func CutAudio[S Cut, E Cut](MusicFile AudioObj, start S, end E) {
// The first parameter is a string.
if reflect.ValueOf(start).Kind() == reflect.String {
MusicFile.CutIfFirstIsString(start, end)
}
// The second parameter is a string.
if reflect.ValueOf(end).Kind() == reflect.String {
MusicFile.CutIfSecondIsString(start, end)
}
}
Here I try to cut the audio file depending on function parameters type:
func main() {
audio := AudioObj{fileName: "music.mp3"}
CutAudio(audio, "00:00:03", 81.0)
CutAudio(audio, 0.3, "01:21:00")
}
Output:
./prog.go:24:32: cannot use start (variable of type S constrained by Cut) as type string in argument to MusicFile.CutIfFirstIsString
./prog.go:24:39: cannot use end (variable of type E constrained by Cut) as type float64 in argument to MusicFile.CutIfFirstIsString
./prog.go:29:33: cannot use start (variable of type S constrained by Cut) as type float64 in argument to MusicFile.CutIfSecondIsString
./prog.go:29:40: cannot use end (variable of type E constrained by Cut) as type string in argument to MusicFile.CutIfSecondIsString
PlayGround: https://go.dev/play/p/1jx1-vHXDdn
It is posibile to convert generic type into the type that I sended to it?
答案1
得分: 1
你可以使用一个简单的类型开关来实现这个,但是代码会有点冗长:
package main
import (
"fmt"
"strconv"
)
type Cut interface {
int | int8 | int16 | int32 | int64 | float32 | float64 | string
}
type AudioObj struct {
fileName string
}
func (A AudioObj) CutIfFirstIsString(from string, to float64) {
// Cut audio file: ("00:00:03", 81.0)
fmt.Println(`Cut audio file: ("00:00:03", 81.0)`)
}
func (A AudioObj) CutIfSecondIsString(from float64, to string) {
// Cut audio file: (0.3, "01:21:00")
fmt.Println(`Cut audio file: (0.3, "01:21:00")`)
}
func CutAudio[S Cut, E Cut](MusicFile AudioObj, start S, end E) {
// 第一个参数是字符串。
if _, ok := any(start).(string); ok {
MusicFile.CutIfFirstIsString(cutToString(start), cutToFloat(end))
}
// 第二个参数是字符串。
if _, ok := any(end).(string); ok {
MusicFile.CutIfSecondIsString(cutToFloat(start), cutToString(end))
}
}
func cutToString[S Cut](cut S) string {
var str string
switch start := any(cut).(type) {
case int:
str = strconv.FormatInt(int64(start), 10)
case int8:
str = strconv.FormatInt(int64(start), 10)
case int16:
str = strconv.FormatInt(int64(start), 10)
case int32:
str = strconv.FormatInt(int64(start), 10)
case int64:
str = strconv.FormatInt(start, 10)
case float32:
str = strconv.FormatFloat(float64(start), 'G', -1, 32)
case float64:
str = strconv.FormatFloat(start, 'G', -1, 64)
case string:
str = start
}
return str
}
func cutToFloat[S Cut](cut S) float64 {
var flt float64
switch end := any(cut).(type) {
case int:
flt = float64(end)
case int8:
flt = float64(end)
case int16:
flt = float64(end)
case int32:
flt = float64(end)
case int64:
flt = float64(end)
case float32:
flt = float64(end)
case float64:
flt = end
case string:
flt, _ = strconv.ParseFloat(end, 64)
}
return flt
}
func main() {
audio := AudioObj{fileName: "music.mp3"}
CutAudio(audio, "00:00:03", 81.0)
CutAudio(audio, 0.3, "01:21:00")
}
英文:
You can do this with a good old type switch, but it is a little bit verbose:
package main
import (
"fmt"
"strconv"
)
type Cut interface {
int | int8 | int16 | int32 | int64 | float32 | float64 | string
}
type AudioObj struct {
fileName string
}
func (A AudioObj) CutIfFirstIsString(from string, to float64) {
// Cut audio file: ("00:00:03", 81.0)
fmt.Println(`Cut audio file: ("00:00:03", 81.0)`)
}
func (A AudioObj) CutIfSecondIsString(from float64, to string) {
// Cut audio file: (0.3, "01:21:00")
fmt.Println(`Cut audio file: (0.3, "01:21:00")`)
}
func CutAudio[S Cut, E Cut](MusicFile AudioObj, start S, end E) {
// The first parameter is a string.
if _, ok := any(start).(string); ok {
MusicFile.CutIfFirstIsString(cutToString(start), cutToFloat(end))
}
// The second parameter is a string.
if _, ok := any(end).(string); ok {
MusicFile.CutIfSecondIsString(cutToFloat(start), cutToString(end))
}
}
func cutToString[S Cut](cut S) string {
var str string
switch start := any(cut).(type) {
case int:
str = strconv.FormatInt(int64(start), 10)
case int8:
str = strconv.FormatInt(int64(start), 10)
case int16:
str = strconv.FormatInt(int64(start), 10)
case int32:
str = strconv.FormatInt(int64(start), 10)
case int64:
str = strconv.FormatInt(start, 10)
case float32:
str = strconv.FormatFloat(float64(start), 'G', -1, 32)
case float64:
str = strconv.FormatFloat(start, 'G', -1, 64)
case string:
str = start
}
return str
}
func cutToFloat[S Cut](cut S) float64 {
var flt float64
switch end := any(cut).(type) {
case int:
flt = float64(end)
case int8:
flt = float64(end)
case int16:
flt = float64(end)
case int32:
flt = float64(end)
case int64:
flt = float64(end)
case float32:
flt = float64(end)
case float64:
flt = end
case string:
flt, _ = strconv.ParseFloat(end, 64)
}
return flt
}
func main() {
audio := AudioObj{fileName: "music.mp3"}
CutAudio(audio, "00:00:03", 81.0)
CutAudio(audio, 0.3, "01:21:00")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论