提问人:R u c k s a c k 提问时间:5/9/2023 最后编辑:R u c k s a c k 更新时间:5/10/2023 访问量:66
如何将print函数作为参数传递给forEach?
How to pass the print function as argument to a forEach?
问:
该函数可以打印整数,可以像 一样调用。我想在数组上做同样的事情。print
print(5)
[Int]
但是,尝试在 上执行相同的操作会失败。forEach
[1,2,3].forEach(print)
给
expression failed to parse:
error: repl.swift:20:17: error: cannot convert value of type
'(Any..., String, String) -> ()' to expected argument type
'(Int) throws -> Void'
[1,2,3].forEach(print)
^
如何让 Swift 在不求助于下面列出的解决方法的情况下执行从 到 的转换?(Any, ... String, String) -> ()
(Int) throws -> Void
函数类型在参数位置上不是逆变的吗,这意味着 因为是 的超类型,是 的子类型(因为与 相同),因此根据里氏替换原理,在这种情况下应该是一个完全可以接受的参数吗?Any
Int
(Any, ... String, String) -> ()
(Int) throws -> Void
()
Void
print
forEach
是 (variadic AND optional!) 参数的数量有问题吗?(Any, ... String, String)
解决方法
这些工作,但对我来说似乎没有必要。
使用速记参数名称创建内联闭包或定义函数都可以。[1,2,3].forEach { print($0) }
func printInt(_ n: Int) { print(n) }; [1,2,3].forEach(printInt)
这表明问题至少部分出在论点的数量上。但是,我不清楚这里发生了什么,并希望得到任何帮助。
答:
如果您只关心使用,这是另一种解决方法:print
extension Sequence {
func printEach() {
for element in self {
print(element)
}
}
}
[1,2,3].printEach()
或者适用于任何类型的解决方法的变体:printInt
func printElement(_ element: Any) {
print(element)
}
[1,2,3].forEach(printElement)
两者都不是很吸引我,只是使用闭包对阅读代码的人来说可能更清楚。print($0)
是 (variadic AND optional!) 参数的数量有问题吗?
(Any, ... String, String)
是的。函数类型参数没有语法,即“这是一个可选参数”。当您被视为第一类对象时,其可选参数将自动变为必需参数。print
let p = print
// p's type is (Any..., String, String) -> Void
func notOptionalPrint(_ items: Any..., separator: String, terminator: String) { ... }
let q = notOptionalPrint
// q's type is also (Any..., String, String) -> Void
此外,第一个参数的类型是 。这与 Any
不同。它不是 or 的超类型,因此 LSP 在这里不适用,即使可选参数问题神奇地解决了。Any...
Int
Any
因此,如果要将其直接传递给 ,则必须以某种方式包装它。与其只包装它,不如考虑包装它:forEach
Int
Any
func print(_ x: Any) {
// need "Swift." here, otherwise infinite recursion
Swift.print(x)
}
然后,由于 LSP,您可以将其直接传递给任何元素类型的集合。forEach
不过就我个人而言,我不会打扰,只是使用 .forEach { print($0) }
评论
(Any..., String, String) -> Void
(Any) -> Void