BLC*_*BLC 4 access-control swift swift4
在升级到Swift4的时候Swift3,我遇到了一些与之相关的问题access control.
这是示例代码.哪个在那里Swift3,过去工作得很好 -
open class MyClass {
private let value: Int
static var defaultValue: Int { return 10 }
public init(value: Int = MyClass.defaultValue) {
self.value = value
}
}
Run Code Online (Sandbox Code Playgroud)
为了使运行中的代码Swift4,我必须改变access control为defaultValue以public.这是Swift4编译版本
open class MyClass {
private let value: Int
static public var defaultValue: Int { return 10 }
public init(value: Int = MyClass.defaultValue) {
self.value = value
}
}
Run Code Online (Sandbox Code Playgroud)
虽然我想知道发生了什么,我试图删除open访问控制MyClass,它允许我删除access标识符defaultValue.甚至可以把它private.
class MyClass {
private let value: Int
private static var defaultValue: Int { return 10 }
public init(value: Int = MyClass.defaultValue) {
self.value = value
}
}
Run Code Online (Sandbox Code Playgroud)
我理解所有访问标识符,但我无法理解这种行为.尤其是在第一种情况xcode迫使我改变access control的defaultValue到public.
请帮忙.
我原来的答复(如下图所示)是现在大多已经过时-弹性模型的开端是在雨燕4.2中实现与引进的@inlinable和@usableFromInline属性,对应于旧@_inlineable和@_versioned属性.
此外,更重要的是,公共可访问函数的默认参数可以引用的规则再次发生了变化.要回顾以前的规则:
在斯威夫特3没有什么访问级别,例如默认参数表达式可以引用(让你的第一个例子,其中执法defaultValue是internal).
在Swift 4中,这样的默认参数只能引用作为模块接口的一部分公开的声明,包括那些在另一个模块(即@_versioned internal)中用户无法直接看到的声明.
但是在Swift 4.2中,随着SE-0193的实现,规则现在是可公开访问的函数的默认参数表达式只能引用可公开访问的声明(不是偶数@inlinable internal或@usableFromInline internal).
我相信这为在模块生成的接口文件中显示默认参数表达式铺平了道路.目前Swift只显示无用= default,但我相信这将改为实际显示默认参数.这只能通过这种新的访问控制限制实际发生(编辑:现在正在发生).
这种变化是由于向弹性模型的工作,已经通过下划线可用属性(@_inlineable,@_versioned,@_fixed_layout),但还没有正式敲定(所以你可能不应该使用这些属性还自己).您可以在此处阅读有关弹性模型的完整建议细节,以及此处的Swift演变讨论.
简而言之,可内联函数的实现和声明作为模块接口的一部分公开,因此在从另一个模块调用时可以内联.因此,内联函数也必须以公开的方式开始(即public或更高).
您遇到的是一种更改,它使公共可访问函数的默认参数表达式可内联,这意味着它们必须可以直接在调用模块的二进制文件中进行评估.这减少了使用来自另一个模块的默认参数值调用函数的开销,因为编译器不再需要为每个默认参数执行函数调用.它已经知道了实施.
我不相信Swift 4本身的发布正式记录了这一变化,但Swift编译工程师Slava Pestov证实了这一点,他说:
Swift 3.1为内联代码添加了弹性诊断,这不是官方支持的功能,但在Swift 4中我们也将这些检查切换为默认参数表达式.
因此,如果您有一个具有默认参数表达式的公共可访问函数(例如MyClass.defaultValue在您的情况下),那么该表达式现在只能引用也是该模块接口的一部分的东西.所以你需要defaultValue公开访问.
不幸的是,目前还没有办法让private函数的声明成为模块接口的一部分(这将允许你在默认的参数表达式中使用它).促进这一点的属性是@_versioned,但(file)private由于Slava Pestov给出以下原因而被禁止:
这将是一个微不足道的改变,以允许
@_versioned在private和fileprivate声明,但有两个陷阱要牢记:
私有符号使用'discriminator'进行损坏,该'discriminator'基本上是文件名的散列.所以现在它将成为ABI的一部分,它似乎很脆弱 - 你不能将私有函数移动到另一个源文件,或重命名源文件.
类似地,现在
@_versioned功能变为公共是ABI兼容的变化.如果您可以使用private @_versioned函数,这将不再有效 ,因为符号名称如果变为符号名称将会更改public.出于这些原因,我们决定反对"
private versioned"作为一个概念.我觉得internal这里已经足够了.
你可以通过以下方式实现这一点@_versioned var defaultValue:
open class MyClass {
private let value: Int
@_versioned static var defaultValue: Int {
return 10
}
public init(value: Int = MyClass.defaultValue) {
self.value = value
}
}
Run Code Online (Sandbox Code Playgroud)
声明MyClass.defaultValue现在作为模块接口的一部分导出,但仍然不能从另一个模块的代码中直接调用(因为它internal).但是,该模块的编译器现在可以在评估默认参数表达式时调用它.但是,如前所述,您可能不应该在此处使用下划线属性; 你应该等到弹性模型最终确定.
| 归档时间: |
|
| 查看次数: |
862 次 |
| 最近记录: |