Go泛型:将底层类型作为[]T返回切片

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

Go generics: return slice of underlying type as []T

问题

我正在开发一个遗传算法库,我使用了一个通用类型声明来表示每个基因的基础类型,即 type Gene[T comparable] struct { Bases: []T }。之所以这样做,是因为并不是每个问题都可以使用特定的数据类型(例如 float64uint8)来解决,所以设计得灵活以适应最终用户的使用情况。我在序列方案中遇到了一个问题,基因之间由 separator []T 分隔:在最后一个基因为空的情况下,序列化会导致出现一个不正常的分隔符,这个分隔符实际上不应该存在,它可能会导致反序列化时将其解析为一个单独的等位基因或只包含分隔符的基因。有两种处理方法:第一种方法是在序列化过程中忽略空的遗传结构并在序列化时排除它们,但这可能会删除有用的结构信息,例如在保存模拟/优化过程中的中间基因组和遗传漂移的情况下;第二种方法是引入一个占位序列来标识空的结构。我希望采用后者。

我希望这个占位序列可以通过翻转 separator []T 中每个基因的位来自动生成,并且我可以使用 "reflect" 包来检测正在使用的类型。然而,当函数的返回签名是 []T 时,我不能返回 []int。我可以像下面这样做,但我不确定这是否是一个好的做法。

func inverseSeparator[T comparable](separator []T) []T {
	result := []T
	switch reflect.TypeOf(separator[0]).Kind() {
	case reflect.Int:
		var v interface{}
		for i := 0; i < len(separator); i++ {
			// 进行位翻转
			v = resultOfBitFlip 
			result = append(result, v.(T))
		}
	// 其他情况
	}
	return result
}

如何将位翻转的结果转换回 T 类型的切片,或者这种方法是否不好?

英文:

I am working on a genetic algorithm library, and I use a generic type declaration for the bases of each gene, i.e. type Gene[T comparable] struct { Bases: []T }. The reason for this is that not every problem can be solved using a particular data type, e.g. float64 or uint8, so it is designed to be flexible to the end-user use cases. I have run into an issue with the sequencing scheme, where genes are separated by separator []T: in the case of an empty final gene, sequencing results in an anomalous separator that should not be there, which can cause desequencing to parse it as a separate allele or a gene containing just the separator. There are two ways to deal with it: the first way is to ignore empty genetic structs and exclude them during sequencing, but this may delete structural information that is useful, e.g. in the case of saving intermediate genomes including genetic drift during a simulation/optimization; the second way is to introduce a placeholder sequence to identify empty structures. The latter is what I wish to do.

I would like for this placeholder sequence to be generated automatically from the separator by flipping the bits of each base in the separator []T, and I can use the "reflect" package to detect which type is being used. However, I cannot return []int when the function return signature is []T. I can do something like the following, but I am unsure if it is good practice.

func inverseSeparator[T comparable](separator []T) []T {
	result := []T
	switch reflect.TypeOf(separator[0]).Kind() {
	case reflect.Int:
		var v interface{}
		for i := 0; i &lt; len(separator); i++ {
			// do the bit flip
			v = resultOfBitFlip 
			result = append(result, v.(T))
		}
	// other cases
	}
	return result
}

What is the best way to go about converting the result of the bit flipping back to a slice of T, or is this a bad approach?

答案1

得分: 1

我认为对附带代码的一个很好的优化是提供一个基本的错误处理机制:

func inverseSeparator[T comparable](separator []T) ([]T, error) {
    switch separator[0].(type) {
    case int:
        var result []T
        for _, val := range separator {
            // 执行位翻转
            // 在翻转位之前,确保 T 是一个有效的数值类型(int、uint 等)
            if n, ok := val.(int); ok {
                // 对整数执行位翻转
                flipped := ^n
                result = append(result, T(flipped).(T))
            } else {
                // 如果类型不支持位翻转,则返回错误
                return nil, fmt.Errorf("不支持的类型进行位翻转:%T", val)
            }
        }
        return result, nil
    // 处理其他类型的情况,如果需要的话。
    default:
        return nil, fmt.Errorf("不支持的类型进行 inverseSeparator:%T", separator[0])
    }
}
英文:
  • I think a good optimization for the attached code is the following, it provides a basic error-handling mechanism:
func inverseSeparator[T comparable](separator []T) ([]T, error) {
    switch separator[0].(type) {
    case int:
        var result []T
        for _, val := range separator {
            // Perform bit flip
            // Make sure T is a valid numeric type (int, uint, etc.) before flipping bits
            if n, ok := val.(int); ok {
                // Perform bit flipping for integers
                flipped := ^n
                result = append(result, T(flipped).(T))
            } else {
                // Return an error if the type is not supported for bit flipping
                return nil, fmt.Errorf(&quot;unsupported type for bit flipping: %T&quot;, val)
            }
        }
        return result, nil
    // Handle other cases for different types, if needed.
    default:
        return nil, fmt.Errorf(&quot;unsupported type for inverseSeparator: %T&quot;, separator[0])
    }
}

huangapple
  • 本文由 发表于 2023年7月22日 01:30:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76740047.html
匿名

发表评论

匿名网友

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

确定