为了账号安全,请及时绑定邮箱和手机立即绑定

Go中新的波浪号令牌〜是什么意思?

Go中新的波浪号令牌〜是什么意思?

Go
慕后森 2022-10-31 15:57:54
Go 引入了新的令牌~。~T 表示具有底层类型 T 的所有类型的集合但是,我看不懂,请人帮忙解释一下。下面是一个例子。type Ordered interface {       Integer | Float | ~string}
查看完整描述

2 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

在泛型提案中,~波浪号标记用于~T表示基础类型为 的类型集T

它在泛型提案中也被称为“近似”约束元素,它用简单的语言解释了它的好处:

列出单一类型本身是没有用的。为了满足约束,我们希望能够说的不仅仅是 int,而是“任何基础类型为 int 的类型”。[...]如果程序使用type MyString string,程序可以使用<带有 type 值的运算符MyString。应该可以用 type 实例化 [a function] MyString

如果您想要正式的参考,语言规范已将基础类型的定义放在其自己的部分中:

每个类型 T 都有一个基础类型:如果 T 是预先声明的布尔、数字或字符串类型之一,或者是类型文字,则相应的基础类型是 T 本身。否则,T 的基础类型是T 在其类型声明中引用的类型的基础类型。

这涵盖了类型文字和其他具有绑定标识符的复合类型的非常常见的情况,或者您在预声明的标识符上定义的类型,这是泛型提案中提到的情况:

// underlying type = struct literal -> itself -> struct { n int }

type Foo struct {

    n int

}


// underlying type = slice literal -> itself -> []byte

type ByteSlice []byte


// underlying type = predeclared -> itself -> int8

type MyInt8 int8


// underlying type = predeclared -> itself -> string

type MyString string

实际含义是类型集只有精确元素的接口约束不允许您自己定义的类型:


// hypothetical constraint without approximation elements

type ExactSigned interface {

    int | int8 | int16 | int32 | int64

}


// CANNOT instantiate with MyInt8

func echoExact[T ExactSigned](t T) T { return t }


// constraints.Signed uses approximation elements e.g. ~int8

// CAN instantiate with MyInt8

func echo[T constraints.Signed](t T) T { return t }

与其他约束元素一样,您可以在联合中使用近似元素,例如constraints.Signed在匿名约束中使用或不使用语法糖。值得注意的是,只有一个 approx 元素的语法糖是有效的:


// anonymous constraint

func echoFixedSize[T interface { ~int8 | ~int32 | ~int64 }](t T) T { 

    return t 

}


// anonymous constraint with syntactic sugar

func echoFixedSizeSugar[T ~int8 | ~int32 | ~int64](t T) T { 

    return t 

}


// anonymous constraint with syntactic sugar and one element

func echoFixedSizeSugarOne[T ~int8](t T) T { 

    return t 

}

如上所述,近似元素的常见用例是需要具有方法的复合类型(切片、结构等)。在这种情况下,您必须绑定标识符:


// must bind identifier in order to declare methods

type ByteSeq []byte


func (b ByteSeq) DoSomething() {}

现在近似元素很方便允许实例化ByteSeq:


// ByteSeq not allowed, or must convert func argument first

func foobar[T interface { []byte }](t T) { /* ... */ }



// ByteSeq allowed

func bazquux[T interface { ~[]byte }](t T) { /* ... */ }


func main() {

    b := []byte{0x00, 0x01}

    seq := ByteSeq{0x02, 0x03}


    foobar(b)           // ok

    foobar(seq)         // compiler error

    foobar([]byte(seq)) // ok, allows inference

    foobar[[]byte](seq) // ok, explicit instantiation, then can assign seq to argument type []byte


    bazquux(b)          // ok

    bazquux(seq)        // ok

}

注意:您不能将近似标记与类型参数一起使用:


// INVALID!

type AnyApprox[T any] interface {

    ~T

}


查看完整回答
反对 回复 2022-10-31
?
哔哔one

TA贡献1854条经验 获得超8个赞

不仅有新的标记,还有接口的新语法。除了方法约束之外,您还可以声明具有类型约束的接口。


为了满足接口,类型必须同时满足方法约束和类型约束。


从文档:


一个接口,表示具有实现 String 方法的底层类型 int 的所有类型。


interface {

  ~int

  String() string

}

对于具有“基础类型”的类型int,这意味着该类型采用以下形式:


type SomeType int

为了满足方法约束,必须声明一个具有指定签名的方法:


func (v SomeType) String() string {

  return fmt.Sprintf("%d", v)

}


查看完整回答
反对 回复 2022-10-31
  • 2 回答
  • 0 关注
  • 451 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号