13 Oct 2017 by 晓晨
In-out 参数不能有默认值的解释只有一个,默认值是字面值,in-out 参数不能接受常量和字面值。
以下是自己的一段错误的思路整理,纯属娱乐。
In-out parameters cannot have default values – The Swift Programming Language (Swift 4): Functions
一个参数,“是否被标记为 in-out”,和“是否有默认值”,这两个属性是互斥的。上面的描述可以理解成,
插播(请跳过)
当我想举属性互斥的另一个例子的时候,我想到了“有毒的食物不能吃”,但是我却拆分成了,“食物是否有毒 ”和“食物是否不能吃”,接着想当然地用了另一种反过来说的方法,”不能吃的食物有毒“,显然这是错误的表述,我分析原因是,“食物是否有毒”和“食物是否不能吃”,这两个属性不是互斥关系。
正确的拆分应该是,“食物是否有毒”和“食物是否能吃”,这样就能得出,
虽然这二者在使用上没有什么区别,但在理解时,拆分成这两种描述会有不同的理解。
对于一个已经被标记为 in-out 的参数,给它默认值意味着传递给它一个字面值(literal value),而 in-out 参数不能接受常量或者字面值,因为它们的值不应该被改变。
对于一个已经有默认值的参数,把它标记为 in-out,有另一个理解,对于传进来的参数,总是把它赋值为默认值。
上面这段的理解明显是错的,默认值只是在不提供该参数的时候生效,在提供该参数时没有任何作用,当然不会总把该参数赋值为这个默认值了。
我为什么会有这样的错误?
对默认值的谁给谁赋值不清晰,究其原因是 in-out 给了默认值两种不同的理解。
“给标记为 in-out 的参数传递一个默认值”,想当然地把这句反转成了“被标记为 in-out 的参数最终总是这个默认值”,并且这句话在脑子里没有清晰的表述。
我是如何发现的?
当我试图把这句话“被标记为 in-out 的参数最终总是这个默认值”表述清楚时,发现表述结果和我心里的感觉不一致。
当我写完上面的话最后补充写出上面的”in-out 给了默认值两种不同的理解“时,我才真正理解了为什么 in-out 参数不能有默认值,因为 in-out 给值的传递的多加了一个反向方向,正常理解时,函数调用者给函数传值,对于有默认值的参数,如果不传值,会用默认值。In-out 函数加的这个反向的传值,是从函数内改变函数传进来的参数,默认值也还可以理解为这个传进来的参数默认会被赋值为这个默认值,尤其当传进来的参数是一个可选值(optional)类型时。
到这里,我发现我需要明确一下默认的定义,
if something happens by default, it happens because you did not do anything to change it – Longman Dictionary of Contemporary English
用到默认值上,就是对这个变量什么都不做的情况下它的值。所以关于 in-out 这个方向值传递的更准确的解释是,如果函数调用者没有对这个参数没有提供值,并且函数内部对这个参数变量什么都没做,那它的值取默认值,当然,这个解释和正常的默认值的解释是冲突的,所以给 in-out 参数提供默认值的解释是有歧义的,所以不能这样做。
重说一遍,给 in-out 参数提供默认值除了会给 in-out 参数传递字面值的问题,还会产生歧义,因为有两种解释,
函数调用者如果不提供该参数(对该参数什么也不做),那么该参数取其默认值传递给函数。
函数内部如果没有接受到这个参数,并且对这个参数没有做任何变动,那么当把这个参数传递会调用者时,取默认值,这个解释不存在实际意义,因为对于调用者来说,没有传递 in-out 参数给函数,函数内给它的默认值也传不出来。
从调用者角度来说,希望给 in-out 参数提供默认值可能是这样的目的,在我给你传变量的时候,使用变量的值并通过变量把改动传回来,当我不给你传变量的时候,你就用默认值,不需要把改动传回来,但对于函数实现来说,没有办法知道这个参数是变量还是字面值。
总结,写出来才能发现自己错了,才有分析错误原因的可能。这里,根本原因是对默认的理解。