检查元类型是否为具有类型为MyProtocol的元素类型的数组 [英] Checking if a metatype is an Array with an Element type of kind MyProtocol
问题描述
协议ResponseProtocol {
associatedtype ResponseType:任何
}
协议MappableProtocol {
init(map:String)
}
我添加了我的数据类 MyDto
class MyDto:MappableProtocol {
需要init(map:String){}
}
和3个不同的响应类
class A1:ResponseProtocol {
typealias ResponseType = String
}
$ b $ class A2:ResponseProtocol {
typealias ResponseType = MyDto
}
class A3:ResponseProtocol {
typealias ResponseType = [MyDto]
}
现在我需要根据 我试过这段代码,但遇到 在我的操场控制台中,对于数组 ResponseType $ c做不同的事情$ c $。
是否为
Array
s
class API {
func test< T:ResponseProtocol>(a:T) - > String {
如果T.ResponseType.self是String.Type {
返回String
}
如果T.ResponseType.self是MappableProtocol.Type {
返回MappableProtocol
}
如果T.ResponseType.self为[Any] .Type {
returnArray< Any> //为什么这是错误的?
}
如果T.ResponseType.self是[MappableProtocol] .Type {
returnArray< MappableProtocol> //为什么这是错误的?
}
如果T.ResponseType.self是[MyDto] .Type {
returnArray< MyDto> //为什么只有这样?
}
returnnotFound
}
}
let api = API()
let t1 = api.test(a: A1())
let t2 = api.test(a:A2())
let t3 = api.test(a:A3())
A3
,我看到 Array< MyDto> ;
,但我预计数组的第一个返回值就像 Array< Any>
。 >如何检查元素
元素 MappableProtocol
[MyDto] 可以自由转换为 [MappableProtocol]
和 [Any]
,这些实际上只是编译器在后台执行的神奇转换(有关更多信息,请参阅本Q& A )。
元类型值不存在相同的转换,这就是为什么Sw ift表示 [MyDto] .Type
不是 [MappableProtocol] .Type
也不是 [任意] .Type
- 它们是不相关的元类型类型。
可能最简单的解决方案就是忘记使用元类型,而是仅仅声明 test(a:)
的不同重载来处理不同的 ResponseType
//'default'测试的重载(a :)
func测试< T:ResponseProtocol>( a:T) - > String {
returnnotFound
}
func test< T:ResponseProtocol>(a:T) - > String where T.ResponseType == String {
returnString
}
func test< T:ResponseProtocol>(a:T) - > String where T.ResponseType:MappableProtocol {
returnMappableProtocol
}
func test< T:ResponseProtocol>(a:T) - > String where T.ResponseType == [MyDto] {
returnArray< MDto>
}
//接受符合ResponseProtocol的类型的测试(a :)的重载,其中
// ResponseType是具有任意Element类型的数组。
func test< T:ResponseProtocol,ResponseTypeElement:MappableProtocol>(a:T) - >字符串
其中T.ResponseType == [ResponseTypeElement]
{
返回Array< MappableProtocol>
$ b $ print(test(a:A1()))// String
print(test(a:A2()))// MappableProtocol
print (test(a:A3()))// Array< MyDto>
//一个符合MappableProtocol,
//但不是MyDto的ResponseType的MappableProtocol。
class Foo:MappableProtocol {required init(map:String){}}
class A4:ResponseProtocol {typealias ResponseType = [Foo]}
print(test(a:A4 ()))// Array< MappableProtocol>
(我删除了您的 API
类只是为了简化事情)
编译器将简单地解决在编译时调用哪个重载,而不是让运行时跳过大量类型转换
如果您坚持处理元类型值,一种可能的解决方案是定义 例如,如果我们定义并符合 现在我们可以使用 I need do different things for different classes. For example I've created the protocols and I'm adding my data class and 3 different response classes now I need do different things depending on I tried this code, but I'm running into problems with In my playground console, for array How can I check for an The problem is that while instances of The same conversions don't exist for metatype values, which is why Swift says that a Likely the simplest solution in your case would just be to forget working with metatypes, and instead just declare different overloads of (I removed your The compiler will simply resolve which overload to call at compile time, rather than having the runtime jump through lots of type-casting hoops. If you insist on working with metatype values, one possible solution is to define a dummy protocol for For example, if we define and conform We can now use
这篇关于检查元类型是否为具有类型为MyProtocol的元素类型的数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! Array
符合的虚拟协议 >类似的Q& A ),然后我们可以将元类型值转换为。然后我们可以声明一个 elementType
静态需求,以便提取数组
的
元素。 self
metatype value,然后我们可以检查其类型以确定数组可以转换为什么。 b
Array
到 _ArrayProtocol
:
protocol _ArrayProtocol {
static var elementType:Any.Type {get}
}
扩展Array:_ArrayProtocol {
static var elementType: Any.Type {
return Element.self
}
}
test(a:)
这样:
func test< T:ResponseProtocol>(a:T) - > String {
如果T.ResponseType.self是String.Type {
返回String
}
如果T.ResponseType.self是MappableProtocol .Type {
returnMappableProtocol
}
//尝试将T.ResponseType.self元类型值转换为存在元元类型
//类型_ArrayProtocol。类型(即符合_ArrayProtocol的类型),
//在这种情况下,这只是Array。
如果让responseType = T.ResponseType.self为? _ArrayProtocol.Type {
//开启元素类型,尝试转换为不同的元类型类型。
switch responseType.elementType {
case MyDto.Type:
returnArray< MyDto>
case是MappableProtocol.Type:
返回Array< MappableProtocol>
默认值:
返回Array< Any>
returnnotFound
}
print(test(a:A1()))// String
print(test(a:A2()))// MappableProtocol
print(test(a:A3()))// Array< MyDto>
print(test(a:A4()))// Array< MappableProtocol>
protocol ResponseProtocol {
associatedtype ResponseType: Any
}
protocol MappableProtocol {
init(map: String)
}
MyDto
class MyDto: MappableProtocol {
required init(map: String) { }
}
class A1: ResponseProtocol {
typealias ResponseType = String
}
class A2: ResponseProtocol {
typealias ResponseType = MyDto
}
class A3: ResponseProtocol {
typealias ResponseType = [MyDto]
}
ResponseType
.Array
sclass API {
func test<T: ResponseProtocol>(a: T) -> String {
if T.ResponseType.self is String.Type {
return "String"
}
if T.ResponseType.self is MappableProtocol.Type {
return "MappableProtocol"
}
if T.ResponseType.self is [Any].Type {
return "Array<Any>" // Why is this false?
}
if T.ResponseType.self is [MappableProtocol].Type {
return "Array<MappableProtocol>" //Why is this false?
}
if T.ResponseType.self is [MyDto].Type {
return "Array<MyDto>" // Why is only this true?
}
return "notFound"
}
}
let api = API()
let t1 = api.test(a: A1())
let t2 = api.test(a: A2())
let t3 = api.test(a: A3())
A3
, I see Array<MyDto>
, but I expected the first return for array like Array<Any>
.Array
where the Element
is of kind MappableProtocol
?[MyDto]
can be freely converted to [MappableProtocol]
and [Any]
, these are really just magical conversions that the compiler does behind the scenes (see this Q&A for more information).[MyDto].Type
is not a [MappableProtocol].Type
nor a [Any].Type
– they are unrelated metatype types.test(a:)
to handle different ResponseType
types.// 'default' overload of test(a:)
func test<T : ResponseProtocol>(a: T) -> String {
return "notFound"
}
func test<T : ResponseProtocol>(a: T) -> String where T.ResponseType == String {
return "String"
}
func test<T : ResponseProtocol>(a: T) -> String where T.ResponseType : MappableProtocol {
return "MappableProtocol"
}
func test<T : ResponseProtocol>(a: T) -> String where T.ResponseType == [MyDto] {
return "Array<MDto>"
}
// overload of test(a:) that accepts a type that conforms to ResponseProtocol, where the
// ResponseType is an Array with arbitrary Element type.
func test<T : ResponseProtocol, ResponseTypeElement : MappableProtocol>(a: T) -> String
where T.ResponseType == [ResponseTypeElement]
{
return "Array<MappableProtocol>"
}
print(test(a: A1())) // String
print(test(a: A2())) // MappableProtocol
print(test(a: A3())) // Array<MyDto>
// A MappableProtocol with a ResponseType that conforms to MappableProtocol,
// but isn't MyDto.
class Foo : MappableProtocol { required init(map: String) { } }
class A4 : ResponseProtocol { typealias ResponseType = [Foo] }
print(test(a: A4())) // Array<MappableProtocol>
API
class just to simplify things)
Array
to conform to (see for example this similar Q&A), which we can then cast the metatype values to. We can then declare an elementType
static requirement in order to extract the Array
's Element.self
metatype value, which we can then inspect the type of in order to determine what the array is convertible to.Array
to _ArrayProtocol
:protocol _ArrayProtocol {
static var elementType: Any.Type { get }
}
extension Array : _ArrayProtocol {
static var elementType: Any.Type {
return Element.self
}
}
test(a:)
like so:func test<T : ResponseProtocol>(a: T) -> String {
if T.ResponseType.self is String.Type {
return "String"
}
if T.ResponseType.self is MappableProtocol.Type {
return "MappableProtocol"
}
// attempt to cast the T.ResponseType.self metatype value to the existential metatype
// type _ArrayProtocol.Type (i.e a type that conforms to _ArrayProtocol),
// in this case, that's only ever Array.
if let responseType = T.ResponseType.self as? _ArrayProtocol.Type {
// switch on the element type, attempting to cast to different metatype types.
switch responseType.elementType {
case is MyDto.Type:
return "Array<MyDto>"
case is MappableProtocol.Type:
return "Array<MappableProtocol>"
default:
return "Array<Any>"
}
}
return "notFound"
}
print(test(a: A1())) // String
print(test(a: A2())) // MappableProtocol
print(test(a: A3())) // Array<MyDto>
print(test(a: A4())) // Array<MappableProtocol>