- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
如您所知,Swift 可以根据用法推断类型。例如,您可以拥有仅在返回类型上不同的重载方法,并且只要编译器能够推断类型就可以自由使用它们。例如,在附加显式类型变量的帮助下,该变量将保存此类方法的返回值。
我发现了一些有趣的时刻。想象一下这个类:
class MyClass {
enum MyError: Error {
case notImplemented
case someException
}
func fun1() throws -> Any {
throw MyError.notImplemented
}
func fun1() -> Int {
return 1
}
func fun2() throws -> Any {
throw MyError.notImplemented
}
func fun2() throws -> Int {
if false {
throw MyError.someException
} else {
return 2
}
}
}
当然,它会像这样工作:
let myClass = MyClass()
// let resul1 = myClass.fun1() // error: ambiguous use of 'fun1()'
let result1: Int = myClass.fun1() // OK
但是接下来你可以这样写:
// print(myClass.fun1()) // error: call can throw but is not marked with 'try'
// BUT
print(try? myClass.fun1()) // warning: no calls to throwing functions occur within 'try' expression
所以看起来像是互斥语句。编译器尝试选择正确的函数;第一次调用时,它试图强制从 Int 转换为 Any,但它试图对第二次调用做什么?
此外,代码如下
if let result2 = try? myClass.fun2() { // No warnings
print(result2)
}
将没有警告,因此人们可能会假设编译器能够在这里选择正确的重载(可能基于事实,其中一个重载实际上什么都不返回,只抛出异常)。
我最后的假设是否正确? fun1()
的警告是否符合逻辑?我们是否有一些技巧可以愚弄编译器或帮助它进行类型推断?
最佳答案
显然,您永远不应该编写这样的代码。它有太多的方式可以咬你,正如你所看到的那样。但让我们看看为什么。
首先,try
在Swift中只是一个装饰。它不适用于编译器。这是给你的。编译器计算出所有类型,然后确定是否需要 try
。它不使用 try
来确定类型。您可以在此处实际看到这一点:
class X {
func x() throws -> X {
return self
}
}
let y = try X().x().x()
您只需要try
一次,即使链中有多个抛出调用。想象一下,如果您根据抛出与非抛出在 x()
上创建重载,这将如何工作。答案是“没关系”,因为编译器不关心 try
。
接下来是类型推断与类型强制的问题。这是类型推断:
let resul1 = myClass.fun1() // error: ambiguous use of 'fun1()'
Swift 永远不会推断出有歧义的类型。这可能是 Any 也可能是
Int`,所以它放弃了。
这不是类型推断(类型已知):
let result1: Int = myClass.fun1() // OK
这也有一个已知的、明确的类型(注意没有 ?
):
let x : Any = try myClass.fun1()
但这需要类型强制(很像您的打印示例)
let x : Any = try? myClass.fun1() // Expression implicitly coerced from `Int?` to `Any`
// No calls to throwing function occur within 'try' expression
为什么这里调用Int
版本? try?
返回一个 Optional(这是一个 Any)。所以 Swift 在这里可以选择返回 Int?
并将其强制转换为 Any
或 Any?
并将其强制转换为 Any
。 Swift 几乎总是喜欢实类型而不是 Any
(而且它讨厌 Any?
)。这是在代码中避免 Any
的众多原因之一。它以奇怪的方式与 Optional 交互。有争议的是,这应该是一个错误,但是 Any
是一种非常奇怪的类型,很难确定它的所有极端情况。
那么这如何应用于 print
? print
的参数是Any
,所以这就像let x: Any =...
的例子而不是let x =...
示例。
在考虑这些事情时要牢记一些自动强制转换:
所以将抛出/非抛出转换与 Any/Any 混合?转换,并将 try?
放入组合中(将所有内容提升为可选),你已经制造了一场完美的困惑 Storm 。
显然,您永远不应该编写这样的代码。
关于可以抛出和不能抛出的方法中的 Swift 类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48386707/
我想做的是让 JTextPane 在 JPanel 中占用尽可能多的空间。对于我使用的 UpdateInfoPanel: public class UpdateInfoPanel extends JP
我在 JPanel 中有一个 JTextArea,我想将其与 JScrollPane 一起使用。我正在使用 GridBagLayout。当我运行它时,框架似乎为 JScrollPane 腾出了空间,但
我想在 xcode 中实现以下功能。 我有一个 View Controller 。在这个 UIViewController 中,我有一个 UITabBar。它们下面是一个 UIView。将 UITab
有谁知道Firebird 2.5有没有类似于SQL中“STUFF”函数的功能? 我有一个包含父用户记录的表,另一个表包含与父相关的子用户记录。我希望能够提取用户拥有的“ROLES”的逗号分隔字符串,而
我想使用 JSON 作为 mirth channel 的输入和输出,例如详细信息保存在数据库中或创建 HL7 消息。 简而言之,输入为 JSON 解析它并输出为任何格式。 最佳答案 var objec
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个以前可能被问过的问题,但我很难找到正确的描述。我希望有人能帮助我。 在下面的代码中,我设置了varprice,我想添加javascript变量accu_id以通过rails在我的数据库中查找记
我有一个简单的 SVG 文件,在 Firefox 中可以正常查看 - 它的一些包装文本使用 foreignObject 包含一些 HTML - 文本包装在 div 中:
所以我正在为学校编写一个 Ruby 程序,如果某个值是 1 或 3,则将 bool 值更改为 true,如果是 0 或 2,则更改为 false。由于我有 Java 背景,所以我认为这段代码应该有效:
我做了什么: 我在这些账户之间创建了 VPC 对等连接 互联网网关也连接到每个 VPC 还配置了路由表(以允许来自双方的流量) 情况1: 当这两个 VPC 在同一个账户中时,我成功测试了从另一个 La
我有一个名为 contacts 的表: user_id contact_id 10294 10295 10294 10293 10293 10294 102
我正在使用 Magento 中的新模板。为避免重复代码,我想为每个产品预览使用相同的子模板。 特别是我做了这样一个展示: $products = Mage::getModel('catalog/pro
“for”是否总是检查协议(protocol)中定义的每个函数中第一个参数的类型? 编辑(改写): 当协议(protocol)方法只有一个参数时,根据该单个参数的类型(直接或任意)找到实现。当协议(p
我想从我的 PHP 代码中调用 JavaScript 函数。我通过使用以下方法实现了这一点: echo ' drawChart($id); '; 这工作正常,但我想从我的 PHP 代码中获取数据,我使
这个问题已经有答案了: Event binding on dynamically created elements? (23 个回答) 已关闭 5 年前。 我有一个动态表单,我想在其中附加一些其他 h
我正在尝试找到一种解决方案,以在 componentDidMount 中的映射项上使用 setState。 我正在使用 GraphQL连同 Gatsby返回许多 data 项目,但要求在特定的 pat
我在 ScrollView 中有一个 View 。只要用户按住该 View ,我想每 80 毫秒调用一次方法。这是我已经实现的: final Runnable vibrate = new Runnab
我用 jni 开发了一个 android 应用程序。我在 GetStringUTFChars 的 dvmDecodeIndirectRef 中得到了一个 dvmabort。我只中止了一次。 为什么会这
当我到达我的 Activity 时,我调用 FragmentPagerAdapter 来处理我的不同选项卡。在我的一个选项卡中,我想显示一个 RecyclerView,但他从未出现过,有了断点,我看到
当我按下 Activity 中的按钮时,会弹出一个 DialogFragment。在对话框 fragment 中,有一个看起来像普通 ListView 的 RecyclerView。 我想要的行为是当
我是一名优秀的程序员,十分优秀!