func cast<T>(_ value: Any, to type: T.Type) -> T { value as! T }
var item: Any = 5
cast(item, to: type(of: item)) // causes an error instead of returning Int
这意味着调用者可以请求任何存在的类型,并且此函数将返回一个。什么都行。它可以是内部Apple类型,不公开公共初始化。它可能是你从未听说过的自定义模块中的随机类型。它可能是一个无人居住的类型(如Never),字面上不能构造,因为故意没有该类型的值。这个函数保证它将返回一个。即使在理论上,也没有办法实现这个函数,除了调用fatalError()并崩溃。 几乎可以肯定的是,您希望返回某个固定类型列表中的一个。你的意思不是Any(例如,你不会返回CBPeripheral)。大多数人的意思是“类似JSON的类型,Stings,Numbers,Arrays,诸如此类的东西。”如果是这样,那么这就是一个协议。 这种模式的一个很好的例子是RangeReplaceableCollection。它需要一个返回空集合的init()方法。语义在这里很重要。Protocols are not just bags of syntax.使用RRC,您可以按照您所描述的方式编写有意义的算法:
func function<T: RangeReplaceableCollection>() -> T {
var item: T = T()
return item
}
func cast<T>(value: Any, to type: T) -> T {
return value as! T
}
let item: Any = "this is a test"
let otherItem: String = "Hello World"
let otherType = otherItem.self // or explicit: String.self()
let casted = cast(value: item, to: otherType)
2条答案
按热度按时间dphi5xsq1#
我怀疑这里有一个关于类型的基本误解。我把这个叫做“下一句是什么?“问题。考虑:
这是无效的,但让我们假设它是允许的。在这一点上,你会对
casted
做什么?下一行代码会是什么样子?什么方法可以在不知道类型的情况下调用?你能把它传递给哪个函数,它接受的限制比Any更严格?它的类型是type
,当然,但这并不能为您带来任何东西。这和Any没什么区别因为你对它的形状一无所知。这就是类型告诉你的:可以对该值做些什么。大部分问题可能来自你的前提:“如果我们需要转换Any类型...”你应该问为什么你一开始就有Any。如果你认为你可以安全地使用
as!
,你必须知道值的类型。为什么Any参与其中?回到那一步,重新设计以摆脱Any,许多类型问题就会消失。对于你问题的后半部分,只考虑签名:
这意味着调用者可以请求任何存在的类型,并且此函数将返回一个。什么都行。它可以是内部Apple类型,不公开公共初始化。它可能是你从未听说过的自定义模块中的随机类型。它可能是一个无人居住的类型(如Never),字面上不能构造,因为故意没有该类型的值。这个函数保证它将返回一个。即使在理论上,也没有办法实现这个函数,除了调用
fatalError()
并崩溃。几乎可以肯定的是,您希望返回某个固定类型列表中的一个。你的意思不是Any(例如,你不会返回CBPeripheral)。大多数人的意思是“类似JSON的类型,Stings,Numbers,Arrays,诸如此类的东西。”如果是这样,那么这就是一个协议。
这种模式的一个很好的例子是RangeReplaceableCollection。它需要一个返回空集合的
init()
方法。语义在这里很重要。Protocols are not just bags of syntax.使用RRC,您可以按照您所描述的方式编写有意义的算法:您还没有给出一个实际的例子来说明您试图用
casted
做什么,所以我将猜测您的用例,如果这是错误的道路,您可以告诉我,您可以解释您所指的实际问题。也许你现在有这样的东西:你不想写
as! Int
,而只想让它成为“无论运行时类型是什么”。所以你写:但这行不通。如果我调用
addOne(value: "x")
,你希望发生什么?在这种情况下,as!
将成功(它不会失败,因为它是自己的类型)。但是+
会做什么呢?如果我传递CBPeripheral或UIViewController会怎么样?这就是Swift类型可以帮助我们避免的全部问题。如果这可以在Swift中工作,那么甚至不需要as!
。你可以只使用Any,它会在运行时被发现,并像JavaScript一样做一些“事情”(可能会崩溃)。或者你可能想写一些东西来处理“任何数字类型”,并试图这样写:
但没有用。那是因为Any是错误的类型。Any几乎总是错误的类型。相反,您需要泛型和协议,它们可以直接安全地处理此问题:
那就不需要选角了如果您发现自己经常调用
as!
,那么您可能使用了错误的类型。rryofs0p2#
考虑你的第一个例子:
为了避免混淆,让我们假设你有一个
otherItem
作为铸造蓝图,它提供了一个具体的类型,那么是的,你可以这样做,但你必须使用Swift提供的静态类型工具,在这种情况下,泛型和.self
来获得示例的类型。下面是一个示例(灵感来自here):
关于你的第二个问题:为了在函数中定义泛型类型的示例,编译器必须知道如何初始化它。因此,它不适用于不提供任何信息的无约束泛型类型T。但是,有一种方法可以做到这一点:
init(a:, b:, ...)
的协议Initializable
(无论您需要什么参数)func function<T: Initializable>() -> ...
let x = T.init(a:, b:, ...)
,因为可以确保类型T提供了这样的初始化器。