当前位置: 首页 > 面试题库 >

为什么我不能在Go中用一种类型的切片替代另一种类型?

胡墨竹
2023-03-14
问题内容

我试图了解Go的类型转换规则。假设我们有以下接口:

type woofer interface {
  woof()
}

type runner interface {
  run()
}

type woofRunner interface {
  woofer
  runner
}

为了满足这些接口,我们有一个dog类型:

type dog struct{}

func (*dog) run()  {}
func (*dog) woof() {}

这两个功能正在使用接口:

func allWoof(ws []woofer) {}

func oneWoof(w woofer) {}

要使用这些方法,我可以编写以下内容:

dogs := make([]woofRunner, 10)
oneWoof(dogs[0])
allWoof(dogs)

第一个功能oneWoof()按预期工作;一个*dog实现所有oneWoof需求,这是一个woof功能。

但是,对于第二个函数allWoof,Go不会编译尝试的调用,并报告以下内容:

不能在allWoof的参数中将狗([] woofRunner类型)用作[] woofer类型

使用类型转换也是不可能的。写作也[]woofer(dogs)失败了:

无法将狗([] woofRunner类型)转换为[] woofer类型

每个成员[]woofRunner都有满足的所有必要功能[]woofer,那么为什么禁止这种转换?

(我不知道这是一样的情况下,在去解释的常见问题,并在堆栈溢出,使人们问转换类型的各种问题Tinterface{}。片/阵列中的每个指针指向一个类型,它是直接转换为另一种类型。出于与传递dog[0]给’oneWoof`
相同的原因,应该可以使用这些指针。)

注意1 :我知道一种解决方案是遍历并逐项转换项目。我的问题是,为什么这是必要的,以及是否有更好的解决方案。

注2 :关于可分配性规则:

当T是接口类型且x实现T时,值x可分配给类型T的变量。

我们不能说切片/数组的类型是否可以分配给其他类型,那么这些类型的数组也可以分配吗?


问题答案:

除了Go拒绝根据此处其他答案中解决的这些方差关系转换切片之外,思考一下 为什么 Go拒绝这样做是有用的,即使两种类型的html" target="_blank">内存中表示形式相同。

在您的示例中,提供woofRunnerss 的切片作为类型的参数[]woofer要求对切片的元素类型进行 协变
处理
。实际上,当从切片中
读取内容时 ,由于a woofRunner 是a
woofer,因此您知道a中存在的每个元素[]woofRunner都会满足读者的需求[]woofer

但是,在Go中,切片是参考类型。当将切片作为参数传递给函数时,将复制切片,但是在调用的函数主体中使用的副本将继续引用相同的后备数组(append超出其容量之前必须进行重新分配)。数组的可变视图(通常是将项目插入集合)需要对元素类型进行
逆向 处理。也就是说,当需要 插入覆盖
type元素的目的是要求函数参数时woofRunner,提供a是可以接受的[]woofer

问题是函数是否要求使用slice参数

  • 从中读取(对于woofers来说,a []woofRunner和a一样好[]woofer),
  • 向它写(对于写woofRunners,a []woofer和a一样好[]woofRunner),
  • 或两者兼有(两者都不可以替代)。

考虑一下,如果Go确实接受协变方式的slice参数,并且有人跟随并allWoof进行如下更改,将会发生什么:

// Another type satisfying `woofRunner`:
type wolf struct{}
func (*wolf) run()  {}
func (*wolf) woof() {}

func allWoof(ws []woofer) {
  if len(ws) > 0 {
    ws[0] = &wolf{}
  }
}

dogs := []*dog{&dog{}, &dog{}}
allWoof(dogs)  // Doesn't compile, but what if it did?

即使Go愿意将a []*dog视为a []woofer,我们也会*wolf*dog此处的数组中加上a
。某些语言通过对尝试的数组插入或覆盖进行运行时类型检查来防止此类事故发生,但是由于Go阻止了我们做到这一点,因此不需要这些额外的检查。



 类似资料:
  • 问题内容: 我正在尝试使用Go语言,并且对它很陌生。我已经成功地完成了教程,现在正在编写一个小程序来评估其通常执行的操作类型的性能。我有一个很长的float32类型切片,需要将其尽可能有效地转换为float64类型的切片。除了遍历slice的元素并通过output [i] = float64(data [i])显式转换单个元素的类型外,还有没有一种方法可以用来转换整个slice而无需迭代?我曾尝试

  • 问题内容: 一个激励人的例子: 实施各种调度“策略”,对“作业”列表进行排序。 一种非常简单的策略是首先执行最短的作业(不考虑其权重/优先级)。 嗯,这种策略只不过是对job.length进行排序,因此让我们使用sort包。定义一个自定义类型,并实现sort.Interface … 好了,现在回到我们的简单策略… 嗯… 问题答案: 首先, 即使您使用like ,也看不到任何定义 。 我认为您的意思

  • 如果按照“字节”->“短”->“int”->“长”->“浮点”->“双倍”的自动转换,那么输出应该打印“双倍”,对吗? (https://www.geeksforgeeks.org/type-conversion-java-examples/)

  • 我是企业架构师的新手。我想知道有没有一种方法可以从已经存在的其他类型的图中自动生成某种类型的图,如果有的话--可以实现哪种类型的图。 例如,序列图是否可以从给定的类图中生成?或者这是不可能的,因为序列图是行为的,而类图是结构的? 提前道谢!

  • 问题内容: 从源(s,s,s)读取图像的最便捷方法是: 但是,然后, 如何转换为格式? 问题答案: 您可以创建所需类型的新BufferedImage,然后在其上绘制原始图像,如下所示:

  • 问题内容: 我想对Java变量进行动态转换,转换类型存储在其他变量中。 这是常规转换: 这就是我要的: 这有可能吗?谢谢! 更新资料 我正在尝试使用HashMap收到的A 填充类。 这是构造函数: 这里的问题是某些类的变量的类型是,如果接收到数字3,它会认为它是类型问题。 问题答案: 是的,可以使用反射 但这没有多大意义,因为必须将结果对象保存在类型变量中。如果你需要变量属于给定的类,则可以将其强