通用切片参数和限制为切片类型的参数有什么区别?

2023-12-05

考虑实验包slices。该软件包是实验性的,因此我知道签名可能会发生变化;我用它来说明问题。

考虑这个包中两个函数的签名,slices.Contains and slices.Grow:

  • func Contains[E comparable](s []E, v E) bool

  • func Grow[S ~[]E, E any](s S, n int) S

第一个参数Contains有类型[]E(切片Es) with E受约束comparable(可比较的类型)。

第一个参数Grow相反有类型S (just S), with S受约束~[]E(其基础类型是切片的类型E)

然而,具有此类类型参数的函数内部允许执行的操作似乎没有任何实际差异。如果我们声明一些具有相同类型参数的伪函数,我们可以看到两者都编译得很好:

正如预期的那样,在这两个函数中我们都可以len/cap, append, range, 分配与make,并索引[ ].

func fakeContains[E comparable](s []E, v E) {
    fmt.Println(len(s), cap(s))

    var e E
    fmt.Println(append(s, e))
    fmt.Println(make([]E, 4))

    for _, x := range s {
        fmt.Println(x)
    }
    fmt.Println(s[0])
    
    fmt.Println(reflect.TypeOf(s).Kind())
}

func fakeGrow[S ~[]E, E any](s S, n int) {
    fmt.Println(len(s), cap(s))

    var e E
    fmt.Println(append(s, e))
    fmt.Println(make(S, 4))

    for _, x := range s {
        fmt.Println(x)
    }
        fmt.Println(s[0])
    
    fmt.Println(reflect.TypeOf(s).Kind())
}

Even reflect.TypeOf(s).Kind() gives reflect.Slice在所有情况下。

这些函数也可以用不同的类型进行测试,并且全部编译:

// compiles just fine
func main() {
    type MyUint64 uint64
    type MyUint64Slice []uint64

    foo := []uint64{0, 1, 2}
    fakeContains(foo, 0)
    fakeGrow(foo, 5)

    bar := []MyUint64{3, 4, 5}
    fakeContains(bar, 0)
    fakeGrow(bar, 5)

    baz := MyUint64Slice{6, 7, 8}
    fakeContains(baz, 0)
    fakeGrow(baz, 5)
}

我的理解中唯一实际的区别是slices.Grow论证s S 不是切片。只是受约束的切片类型。事实上reflect.TypeOf(s)当 arg 是以下实例时给出不同的输出type MyUint64Slice []uint64:

  • Contains与精氨酸s []E gives reflect.TypeOf(s) -> []uint64
  • Grow与精氨酸s S gives reflect.TypeOf(s) -> main.MyUint64Slice

然而,我并不清楚这是什么实际的两者之间的区别。

游乐场的代码:https://gotipplay.golang.org/p/zg2dGtSJwuI

Question

这两个声明在实践中是否等效?如果不是,我什么时候应该选择其中之一?


重要的是如果您必须返回与参数相同(可能命名)类型的切片.

如果您不必返回切片(只需返回一些其他信息,例如bool报告是否包含该值),您不需要使用本身限制为切片的类型参数,您可以仅对元素使用类型参数。

如果必须返回与输入类型相同的切片,则必须使用本身限制为切片的类型参数(例如~[]E).

为了演示,让我们看看这两个实现Grow():

func Grow[S ~[]E, E any](s S, n int) S {
    return append(s, make(S, n)...)[:len(s)]
}

func Grow2[E any](s []E, n int) []E {
    return append(s, make([]E, n)...)[:len(s)]
}

如果您传递将切片作为其基础类型的自定义类型的切片,Grow()可以返回相同类型的值。Grow2()不能:它只能返回未命名切片类型的值:[]E.

以及演示:

x := []int{1}

x2 := Grow(x, 10)
fmt.Printf("x2 %T len=%d cap=%d\n", x2, len(x2), cap(x2))

x3 := Grow2(x, 10)
fmt.Printf("x3 %T len=%d cap=%d\n", x3, len(x3), cap(x3))

type ints []int
y := ints{1}

y2 := Grow(y, 10)
fmt.Printf("y2 %T len=%d cap=%d\n", y2, len(y2), cap(y2))

y3 := Grow2(y, 10)
fmt.Printf("y3 %T len=%d cap=%d\n", y3, len(y3), cap(y3))

输出(尝试一下去游乐场):

x2 []int len=1 cap=12
x3 []int len=1 cap=12
y2 main.ints len=1 cap=12
y3 []int len=1 cap=12

如你看到的Grow2(y, 10)接收一个类型的值main.ints但它返回一个类型的值[]int。这不是我们想要的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通用切片参数和限制为切片类型的参数有什么区别? 的相关文章

随机推荐

  • Facebook cURL 以我身份发帖?

    创建 Facebook 应用程序 使用 cURL 从应用程序发布消息 但它似乎是由我发布的 我怎样才能从应用程序发布 这是我的 cURL attachment array access token gt token message gt m
  • 由于循环导入而无法导入 opencv

    当尝试在 jupyter 实验室笔记本中导入 opencv 时 import cv2 我收到此错误 AttributeError 部分初始化的模块 cv2 没有属性 gapi wip gst GStreamerPipeline 很可能是由于
  • 如何在 Android 上创建 .csv

    我的目标是从表格创建 csv 文件 以打印报告 然后我可以将此 csv 文件存储到我的 SD 卡中 我已经提到了一些与此类似的问题 但他们要求提供一个 jar 文件 有没有其他方法可以不用jar文件来集成呢 在组件 au com bytec
  • MVVM - WPF DataGrid - AutoGenerateColumn 事件

    我目前正在仔细查看出色的Laurent 的工具包和我有以下问题 从 Blend 4 开始 我为 Loaded 事件添加了一个 EventTrigger 在我的 ViewModel 中我有以下内容 public RelayCommand rc
  • 内部录音程序[关闭]

    Closed 这个问题需要多问focused 目前不接受答案 注意 这不是需要使用麦克风的东西 我想在内部录制音频 我想用 C 或 Java 编写一个程序来记录发送到计算机扬声器的音频数据 最终产品将允许用户点击 录制 按钮 当前正在播放的
  • For 循环影响递归变量

    我正在尝试使用递归创建一个函数 该函数可以从帕斯卡三角形内的任何序列中获取任何项 基本上使用自然数作为第一个集合的加法序列 然后使用之前的每个集合作为加法序列 始终从 1 开始 单纯形数 我目前正在学习 JavaScript 并正在做我已经
  • 自定义hugo学术主题中的“关于”小部件

    我通过 RStudio blogdown 使用hugo academic 主题来构建我的网页 示例页面在这里 https themes gohugo io theme academic 我想添加第二份非学术清单兴趣低于学术的 这可能吗 在配
  • 将字符串中的整数提取到数组中

    我需要提取integers from a String到一个数组中 我已经得到了integers 但我无法将它们放入数组中 public static void main String args String line First numb
  • 如何根据条件和参数数量启用结构体?

    我想创建一个元函数 如果向其传递超过 1 个参数 则返回特定类型 如果仅向其传递一个参数 则返回基于条件的另一种类型 该条件是任意的 因此需要enable if或类似的东西 但对于这个例子 我只是将其作为类型比较 让我们将其简化为以下内容
  • 估计全局辐照度的漫射和直接分量

    我正在寻找分离全局辐照度的漫射和直接分量 并找到了 Erbs 模型来在 pvlib 中执行此操作 请参阅pvlib irradiance erbs 但是 我得到了非常奇怪的结果 我预计直接法向辐照度 DNI 会低于全局水平辐照度 GHI 或
  • 找不到-lpthread

    我正在尝试交叉编译 samba 服务器 config 工作得很好 但是当我想用 make 构建时 提示说 Linking shared library bin libsmbclient so 0 opt qnx630 host linux
  • Powershell Import-CSV 如何跳过直到基于字符串的特定行?

    你好 我的 CSV 文件是这样的 BEGINPROPERTIES total candidate create 2 duration 0 00 00 433 internal audit session id 1397055568 inte
  • 使用正则表达式的codingbat wordEnds

    我正在尝试解决wordEnds来自codingbat com使用正则表达式 给定一个字符串和一个非空单词字符串 返回由字符串中该单词每次出现之前和之后的每个字符组成的字符串 忽略单词前后没有字符的情况 如果字符位于两个单词之间 则可能会包含
  • 将文件上传到远程服务器

    我需要将文件从驻留在 Web 服务器中的 ASP NET C 页面上传到远程服务器 我设法使用以下代码从本地主机将文件上传到远程服务器 string serverPath xx xxx xx xx Folder FileUpload1 Fi
  • 使用索引或位图索引扫描对时间戳进行高效的 PostgreSQL 查询?

    在 PostgreSQL 中 我的日期字段上有一个索引tickets桌子 当我将领域与now 查询非常有效 explain analyze select count 1 as count from tickets where updated
  • 多个 Mobilefirst-Server 工件并发部署

    我使用批处理过程来部署 MFP v7 工件 wlapp 和适配器 该过程基于 worklight ant deployer jar 中定义的标准 ant 任务 MFP 环境在 WAS 单元上运行 并由管理多个 WLRuntime 的单个 A
  • xpath 表达式中的属性和 count()

    给定以下 XML 文件 a b b a
  • 如何使用python docx获取word文档中文本的实际样式

    我正在使用 python docx 库来阅读MS word文件 docx 当我阅读段落时 我使用字体函数来获取所有样式属性 但有时它会给None对于字体大小属性 有什么方法可以获取段落包含的实际字体大小 下面给出了我用来解析段落的示例代码
  • Java LineNumberTable:条目说明

    如果我反汇编我的类文件 我会得到以下形式的 LineNumberTables LineNumberTable line 204 0 line 205 9 line 208 57 line 209 63 line 210 72 line 21
  • 通用切片参数和限制为切片类型的参数有什么区别?

    考虑实验包slices 该软件包是实验性的 因此我知道签名可能会发生变化 我用它来说明问题 考虑这个包中两个函数的签名 slices Contains and slices Grow func Contains E comparable s