- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我真的很困惑地发现下面的代码只是拒绝与典型的“Unexpectedly found nil while unwrapping an Optional value”异常一起崩溃,这是你期望从强制展开 bar
。
struct Foo {
var bar: Bar?
}
struct Bar {}
var foo = Foo()
debugPrint(foo.bar) // nil
debugPrint(foo.bar!.dynamicType) // _dynamicType.Bar
dynamicType
似乎以某种方式 能够回退到 bar
的定义类型——而不会崩溃。
请注意,这似乎仅在 Bar
被定义为 value 类型(如 @dfri says )时发生,Foo
是 struct
或 final class
(如 pointed out by @MartinR )& foo
是可变的。
我最初确实认为它可能只是编译器优化,因为 bar
的类型在编译时是已知的,因此强制展开可以被优化掉——但它当 Bar
被定义为 final class
时也会崩溃。此外,如果我将“优化级别”设置为 -Onone
,它仍然有效。
我倾向于认为这是一个奇怪的错误,但需要一些确认。
这是 dynamicType
的错误或功能,还是我只是在这里遗漏了什么?
(使用带有 Swift 2.2 的 Xcode 7.3)
这在 Swift 4.0.3 中仍然可以重现(用一个更小的例子):
var foo: String?
print(type(of: foo!)) // String
这里我们使用 dynamicType
的继承者 type(of:)
来获取动态类型;和前面的例子一样,它不会崩溃。
最佳答案
这是 indeed a bug ,已修复by this pull request ,它应该会进入 Swift 4.2 版本,一切顺利。
如果有人对复制它的看似奇怪的要求感兴趣,这里有一个(不是真的)简要概述发生了什么......
调用标准库函数 type(of:)
被类型检查器解析为特殊情况;它们在 AST 中被一个特殊的“动态类型表达式”所取代。我没有调查它的前身 dynamicType
是如何处理的,但我怀疑它做了类似的事情。
当为这样的表达式发出中间表示(具体为 SIL)时,the compiler checks to see如果生成的元类型是“厚”的(对于类和协议(protocol)类型的实例),如果是,则发出子表达式(即传递的参数)并获取其动态类型。
但是,如果生成的元类型是“瘦”的(对于结构和枚举),编译器会在编译时知道元类型值。因此,仅当子表达式有副作用时才需要对其求值。这样的表达式作为“忽略的表达式”发出。
问题出在发出被忽略的表达式的逻辑上,这些表达式也是左值(一个可以分配给并作为 inout
传递的表达式)。
Swift 左值可以由多个组件组成(例如,访问属性、执行强制解包等)。一些组件是“物理的”,这意味着它们会产生一个要使用的地址,而其他组件是“逻辑的”,这意味着它们由 getter 和 setter 组成(就像计算变量一样)。
问题是物理组件被错误地认为是无副作用的;然而,强制展开是一个物理组件,不是没有副作用(键路径表达式也是一个非纯物理组件)。
因此,如果表达式左值仅由物理组件组成,则带有强制展开组件的忽略表达式左值将错误地不评估强制展开。
让我们看一下当前崩溃的几个案例(在 Swift 4.0.3 中),并解释为什么该错误被回避并且正确评估了强制解包:
let foo: String? = nil
print(type(of: foo!)) // crash!
这里,foo
不是左值(因为它被声明为 let
),所以我们只是获取它的值并强制解包。
class C {} // also crashes if 'C' is 'final', the metatype is still "thick"
var foo: C? = nil
let x = type(of: foo!) // crash!
这里,foo
是一个左值,但编译器认为生成的元类型是“厚”的,因此取决于 foo 的值!
,因此加载了左值,因此计算了强制解包。
我们也来看看这个有趣的案例:
class Foo {
var bar: Bar?
}
struct Bar {}
var foo = Foo()
print(type(of: foo.bar!)) // crash!
它会崩溃,但如果 Foo
被标记为 final
则不会。无论哪种方式,生成的元类型都是“瘦”的,那么 Foo
是 final
有什么区别呢?
嗯,当 Foo
是非 final 时,编译器不能仅通过地址引用属性 bar
,因为它可能被子类覆盖,这很可能将其重新实现为计算属性。因此,左值将包含一个逻辑组件(对bar
的getter 的调用),因此编译器将执行加载以确保此getter 调用的潜在副作用被评估(力展开也将在负载中评估)。
然而,当 Foo
是 final
时,对 bar
的属性访问可以建模为物理组件,即它可以被引用地址。因此编译器错误地假设因为所有左值的组件都是物理的,所以它可以跳过对它的评估。
无论如何,这个问题现在已经解决了。希望有人觉得上面的漫谈有用和/或有趣:)
关于swift - 为什么在强制解包的 nil 可选值类型上使用 dynamicType 有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36824048/
我一直很难编辑我的 .htaccess 文件来一起做这三件事。我已经能够分别获得每个部分,但我只是不明白逻辑流程如何使它们全部工作。 这是我能够使用 bluehost support 上的演示进行整合
我制作的宏将模板工作簿保存为两个单独的文件。每个测试保存一个(位置 1、2、3 或 4),然后在另一个宏中使用每个测试的数据。第二个是保留用于备份的原始数据文件。现在的问题是每次我在每个位置运行测试并
我正在写一篇关于如何使用 OCaml 的模块系统而不是 Java 的 OO 系统(一个有趣的视角)的博客文章。我遇到了一些我不理解的关于强制的事情。下面是一个基本模块和两个包含它的模块: module
我有一段将被执行多次(5,000+)的代码,以及一个仅在第一次为真的 if 语句。我曾想过使用“FIRST”变量并每次都进行比较,但每次都检查它似乎是一种浪费,即使我知道它不需要。 bool FIRS
首先,我是 Perforce 的新手,我主要通过其文档进行学习。 因此,我们即将从 CVS 迁移到 Perforce,我最近学到了一个避免更改每个工作区的 P4CLIENT 的好方法,即在工作区根目录
我正在为一段代码编写测试,其中包含我试图涵盖的 IOException 捕获。 try/catch 看起来像这样: try { oos = new ObjectOutputStream(new
我正在尝试在新闻项目滚动之间添加延迟。我知道 $.each() 通过不等待动画完成来完成其工作,但我想知道如何制作它,以便一次向上滚动一个项目并等到最后一个动画完成后再继续在循环中。 $(functi
假设已经编写了一个方法,需要一个排序列表作为其输入之一。当然这将在代码中进行注释和记录,param 将被命名为“sortedList”,但如果有人忘记,则会出现错误。 有没有办法强制输入必须排序?我正
我正在尝试将传入请求重定向到 https://www.domain.com/和所有 https://www.domain.com/ {所有页面}并且没有什么麻烦。我试过的方法: 添加此行:Redire
我将如何实现以下内容: title_selection = raw_input("Please type in the number of your title and press Enter.\n%
我有一个登录表单,我需要强制关闭自动完成功能。我试过了 jquery: $('#login').attr("autocomplete", "off"); HTML: Javascript:docume
我想知道我应该怎么做才能强制从 dev 分支 merge 到我的 master 分支?使用“git merge dev”会导致很多冲突。但是,我不想单独处理它们。相反,我只是想使用我的 dev 分支中
当安装 Hl7.Fhir.DSTU2 和 Hl7.Fhir.R4 这两个 Nuget 包时,我们得到如下信息: DSTU2 包似乎在使用 Hl7.Fhir.Support.Poco 版本 3.4.0
我正在尝试让一个功能组件在 testFn 执行时强制重新渲染。我想使用状态来做到这一点(如果有更好的方法请说出来),这似乎成功地强制重新渲染但只有两次,然后什么都没有。 我构建了一个简单的演示来模拟这
默认情况下,g++ 似乎会省略未使用的类内定义方法的代码。示例 from my previous question : struct Foo { void bar() {} void baz(
我正在尝试使用 here 中介绍的技术使我的网站背景以比内容慢的速度滚动。我不希望背景固定,只希望更慢。 这是 HTML 的样子: .parallax { perspective: 1px;
我能找到的最相似的问题是 'how to create a row of scrollable text boxes or widgets in flutter inside a ListView?'
我有以下 eslint 配置: "object-curly-newline": ["error", { "ImportDeclaration": "never",
我正在使用 TinyMCE 插件并将 valid_elements 选项设置为: "a[href|target:_blank],strong/b,em/i,br,p,ul,ol,li" 即使没有列出数
您好,我想使用以下命令放置多行描述 p4 --field Description="MY CLN Header \\n my CLN complete description in two -thre
我是一名优秀的程序员,十分优秀!