为什么字节切片不满足任意切片的泛型类型约束?

问题描述 投票:0回答:1

我有以下带有两个通用函数的代码。它们都执行将切片附加到自身并返回结果的简单操作。然而,调用更简单、更直接的函数

cat1
会产生编译错误,而调用定义更笨拙的函数
cat2
及其多余且显式的切片元素
E
声明会按预期工作。为什么
cat1
不被接受?

func cat1[S ~[]any](s S) S {
  return append(s, s...)
}

func cat2[S ~[]E, E any](s S) S {
  return append(s, s...)
}

func main() {
  fmt.Println(string(cat2([]byte("hello"))))
}

调用

cat1
时的错误是:

[]byte does not satisfy ~[]any ([]byte missing in ~[]any)

https://go.dev/play/p/IJzCEiPglgA

go generics slice type-constraints
1个回答
0
投票

类型约束必须是接口,但是关键字

interface
作为语法糖几乎总是被省略。

因此,当您使用

~[]any
作为类型约束时,您实际编写的是:

interface{ ~[]any }

在此界面中,

~[]any
是一个类型术语。什么类型可以满足这个约束?与所有限制一样:

如果 T 是 C 定义的类型集的元素,则类型参数 T 满足类型约束 C

由约束定义的类型集

C
又名
interface{ ~[]any }
是类型文字
[]any
以及以
[]any
作为基础类型的所有类型。例如:

type Foo []any

[]byte
不包含在
interface{ ~[]any }
的类型集中,就像在通用代码之外,您无法将
[]byte
分配给
[]any
:

var a []byte
var b []any
b = a // compilation error

正如 @JimB 在 a comment 中提到的,

byte
any
具有不同的内存布局,因此它们的复合类型不能相互分配。

现在,当您单独使用

any
作为类型约束时,情况会发生变化。
any
interface{}
(空接口)的别名。在这种情况下,没有语法糖。约束只是
interface{}
,它是一个没有方法和类型术语的接口。所有类型都实现它,包括
byte

您的第二个函数

cat2
是定义可以是任何切片的类型参数
S
的唯一正确方法:

func cat2[S ~[]E, E any](s S) S {
  return append(s, s...)
}

这里

E
被限制为任何类型,并且
S
解析为
E
的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.