子类化结构体或类似的东西

3
我了解结构体和类(以及协议)的基本工作原理。我有一个相当常见的情况:
我需要具有运算符的通用值类型,这些值类型在分配时确实必须进行复制。 这些类型具有复杂的结构,我希望能够通过子类专门化,否则将在各处复制代码,并且这将是糟糕的编程。
我尝试过协议和扩展,但由于协议不是通用的,因此我无法定义我想要的(通用)运算符。 如果我使用类,则不会在分配时进行复制。
今天的例子是我有Matrix,其中包含SquareMatrix和特定的方阵函数。有运算符,矩阵可以由符合我的环协议的任何内容填充。我尝试在关联类型协议中定义几乎所有功能,并进行扩展。
编辑:我真的想知道我应该编写什么代码。在矩阵情况下,我需要能够像其他任何东西一样传递方阵,因此子类化是唯一的选择吗?也许我错了。主要问题是当我必须编写涉及内部值的函数时,我必须知道通用类型参数才能做任何有用的事情。例如,在定义加法时,我必须创建一个新矩阵并声明其通用类型,但是当我只知道某些东西是(非通用)协议时,我从哪里获取它?它的真实类型是通用的,尽管协议具有此关联类型,但我无法将其取出。 解决方案感谢亚历山大·莫姆克利奥夫。基本上需要更多的工作将代码完全移入协议扩展中,并为所有相关类型使用'Self'。在扩展中,编译器对通用类型很满意。
代码是私有的,很抱歉我无法在这个问题中粘贴任何内容。感谢您的耐心和帮助。

3
请提供你尝试过的代码和实际遇到的问题。 - shallowThought
2个回答

13
我想到了至少两个原因,使得结构体继承/多态不可能实现:
1. 结构体是按值存储和移动的。这要求编译器在编译时知道结构体的确切大小,以便知道在结构体实例的开始后复制多少字节。假设有一个结构体A和一个从A继承的结构体B。每当编译器看到类型为 A 的变量时,它无法确定运行时类型是否真的是 A,还是使用了 B。如果 B 添加了 A 没有的新存储属性,则 B 的大小将与 A 不同(更大)。编译器将无法确定这些结构体的运行时类型和大小。
2. 多态需要一个函数表。函数表将作为结构体类型的静态成员存储。但要访问此静态成员,每个结构体实例都需要一个实例成员,其中编码实例的类型。这通常称为“isa”指针(例如,此实例是 A 类型)。对于每个实例,这将是8个字节的开销(在64位系统上)。考虑到 Int、Bool、Double 和许多其他常见类型都实现为结构体,这将是不可接受的开销。想想,一个 Bool 是一个一字节的值,需要8个字节的开销。效率只有11%!
因此,协议在 Swift 中扮演了重要的角色,因为它们允许您介绍类似继承的行为,而不会出现这些问题。

谢谢,这很有道理。我大部分已经知道了。我的结构体相当大,所以开销不是问题。 现在我想起来,在这种情况下我只能使用类,因为我需要一个类型具有更多的功能,但有时也需要假装它是简单版本。唉,今天没有值类型适用于我。 我将修改我的问题,以便针对“最佳策略”。 - Richard Birkett
1
@Richard Birkett 声明一个协议 Matrix,在扩展中添加默认行为,然后你的 Struct SquareMatrix 就可以成为具有额外行为的 Matrix。值类型确认协议! - Irfan
泛型函数接受两者的问题。请参见编辑。 - Richard Birkett
1
它只是无法工作,因为输入具有非通用类型,那么函数代码需要知道这些类型。什么? - Alexander
1
你希望我如何帮助你? - Alexander
显示剩余5条评论

0
首先,在Swift中,如果您使用“associatedtype”,协议可以是通用的。
另一方面,您需要值语义,因此可以使用“写时复制”方法。这将为您的类提供值语义(因此它们与结构一样安全)。
这两种方法都可以用来解决您的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接