方法如何访问调用者的属性?
Posted
技术标签:
【中文标题】方法如何访问调用者的属性?【英文标题】:How can a method access a property of a caller? 【发布时间】:2017-06-23 13:21:55 【问题描述】:我有一个具有 2 个属性的结构,它们相互依赖。可以通过将其中任何一个作为参数传递来创建一个实例,然后初始化程序将调用一个函数来计算相应的另一个。此计算需要另一个变量的值,该变量在我的操场顶部声明为全局变量:
var grid: Int = 8
struct myStruct
var valueAsTuple: (Int,Int,Int)
var valueAsInt: Int
init(_ value: (Int,Int,Int))
self.valueAsTuple = value
self.valueAsInt = 0
self.valueAsInt = getIntFromTuple(value)
init(singleInt: Int)
self.valueAsTuple = (0,0,0)
self.valueAsInt = singleInt
self.valueAsTuple = getTupleFromInt(singleInt)
func getIntFromTuple(tuple: (Int,Int,Int)) -> Int
// do some math using the global grid variable
return result
func getTupleFromInt(int: Int) -> (Int,Int,Int)
// do some math using the global grid variable
return result
这在操场上运行良好。然而,最后 myStruct 永远不会被用作单个实例,而是另一个结构将保存一个 myStructs 数组。这个封装结构会有一个属性“grid”,在计算myStruct的属性时应该使用这个属性。
可以创建封装属性的多个实例,每个实例都具有不同的“网格”值,因此在外部结构的一个实例中创建的 myStruct 实例将在另一个实例中得到不同的结果属性比在不同实例中创建的属性。
我是面向对象编程的新手,所以我仍在学习如何组织我的代码以实现我的特定目标。
我试图将 myStruct 嵌套到外部结构中,但出现错误:“实例成员 'grid' 不能用于类型 'myStruct'。
将 grid var 更改为 static 会使嵌套结构看到它,但这将无法为外部结构的每个实例赋予不同的网格值。
那么,简而言之,对必须使用其周围范围属性的对象进行编码的快速方法是什么?
编辑:
我试着举一个更清楚的例子:
假设你有很多鸡蛋,你想把它们存放在盒子里。一个鸡蛋可以有一个绝对数(m),它可以是盒子(o)中的第(n)个鸡蛋。您可以告诉初始化程序将鸡蛋存储在绝对位置 (m) 或特定框的特定位置。
现在有些盒子可以容纳 6 个鸡蛋,而这样的盒子可以容纳 10 个。当然,我可以在每次初始化新鸡蛋时传递盒子的容量(“网格”值),但我正在寻找的是让初始化程序知道我要附加到的数组具有哪个框大小的便捷方法:
shelfWithSmallBoxes.boxesArray.append(21)
// now there is an egg at absolute position 21
print(shelfWithSmallBoxes.boxesArray.last.asTuple
shelfWithLargeBoxes.boxesArray.append(21)
// also here is an egg at absolute position 21
print(shelfWithLargeBoxes.boxesArray.last.asTuple
the first result should be (4,3), as the egg would be placed in the 4th box at position 3, the second result should be (3,1)
我认为,这不是一个太奇特的问题,我只是太新手,无法判断哪种方法是最佳实践。
【问题讨论】:
你的描述让我很困惑。你想:(a) 将一个myStruct
s 数组包装在一个外部结构中,并且 (b) 让它们共享对同一个 grid
变量的访问吗?
是的,这是我的意图。
【参考方案1】:
一种可能的解决方案是将valueAsTuple
和value
之间的计算移至父结构。
看起来您正在存储网格索引,并且计算取决于网格大小。
这类似于 Swift 中现有的 Collection API,其中集合使用以下函数对其索引进行数学运算:
collection.index(after: anIndex)
collection.distance(from: anIndex, to: anotherIndex)
其他可能性是:
-
将
grid
变量作为实例变量包含在MyStruct
中。
在MyStruct
中存储对父类型的引用(仅当父类型是类时才有效)
将grid
存储在父结构中,并将其传递给需要它的每个函数调用。
【讨论】:
【参考方案2】:将grid
作为初始化程序的一部分传递。这是一个很常见的模式:
init(_ value: (Int,Int,Int), in grid: Grid)
init(singleInt: Int, in grid: Grid)
没有规则说您传递给init
的东西必须是目标的属性。
在您的“鸡蛋”示例中,我认为令人困惑的是(至少在您的示例中)鸡蛋没有理由知道它们在哪里。这里有趣的类型是集合(框或网格)。它应该对自身内部的位置很聪明。鸡蛋应该对位置保持沉默。似乎问题在于您正在尝试将框类型设置为Array
,但这不是正确的工具;这个问题还不够聪明。创建一个Box
类型(或Grid
类型)。它可能包含一个Array
作为后备存储,但这并不重要。将它们保存为 [Int: Egg]
可能更容易(如果 Eggs 没有内部结构,甚至只是作为索引的 Set
)。
这里的关键是事物通常不应该将自己插入集合或在集合内部管理自己。应该将事物传递给要插入和管理的集合。
【讨论】:
我在想那个,我会试一试。我还没有弄清楚,如何确保每个实例都必须由包装结构的实例“拥有”。 这里的“拥有”是什么意思?记住;这些是价值观。没有人可以“拥有”数字 4。数字 4 可能是计算的结果,但它只是一个值。如果您需要这些元素具有强烈的所有权概念,则建议使用引用类型(类),而不是值类型(结构)。 我知道“拥有”一词在编程语言方面具有一定的含义,但我不是指这个。我的意思是 myStruct 的任何实例都应该只作为数组的元素存在,这是外部结构的属性。当我将这样一个数组的一个元素附加到外部结构的另一个实例的相应数组中时,应该重新计算它以匹配其新家的“网格”值。 myStruct 的任何实例都不应该单独存在于 outerStruct 实例的数组属性之外。 "myStruct 的任何实例。"您说“实例”的事实表明您的意思是引用类型。值类型没有实例。它们只是价值观。在您使用“struct”的任何地方替换“数字 4”(这不是开玩笑;“4”实际上是 Swift 中的结构)。不“作为元素存在”的值。如果您可以谈论它存在的“位置”,那么它不是值类型。它是一个引用类型。 (再次考虑 4。)如果这种行为对您很重要,您需要使用类,而不是结构。具有相同属性值的两个结构必须无法区分。 这里的重点是结构体 100% 由其属性值定义。如果任何其他事物定义了它(例如它在层次结构中的位置),那么它是一个引用类型,而不是一个值类型,并且应该作为一个类来实现。这很重要,因为当您传递或返回一个结构时,它会被复制,因此您不能谈论结构“在哪里”;它本质上会有很多克隆。以上是关于方法如何访问调用者的属性?的主要内容,如果未能解决你的问题,请参考以下文章