Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics Swift:检查通用类型是否符合协议_Generics_Swift - Fatal编程技术网

Generics Swift:检查通用类型是否符合协议

Generics Swift:检查通用类型是否符合协议,generics,swift,Generics,Swift,我有一个协议,我这样定义: protocol MyProtocol { ... } 我还有一个通用结构: struct MyStruct <T> { ... } 但这会引发一个编译器错误: error: cannot downcast from 'T.Type' to non-@objc protocol type 'MyProtocol' let conforms = T.self is MyProtocol ~~~~~

我有一个协议,我这样定义:

protocol MyProtocol {
   ...
}
我还有一个通用结构:

struct MyStruct <T>  {
    ...
}
但这会引发一个编译器错误:

error: cannot downcast from 'T.Type' to non-@objc protocol type 'MyProtocol'
   let conforms = T.self is MyProtocol
                  ~~~~~~ ^  ~~~~~~~~~~

我也尝试过一些变体,比如
T.self是MyProtocol.self
T是MyProtocol
,使用
==
代替
。到目前为止,我还没有取得任何进展。有什么想法吗?

您需要将协议声明为
@objc

@objc protocol MyProtocol {
    ...
} 
摘自苹果的《Swift编程语言》一书:

只有当您的协议被标记为@objc属性时,才能检查协议的一致性,如上面的HasArea协议所示。此属性表示协议应公开给Objective-C代码,并在与Cocoa和Objective-C一起使用Swift中进行了描述。即使您没有与Objective-C进行互操作,如果您希望能够检查协议一致性,也需要使用@objc属性标记您的协议

还要注意,@objc协议只能由类采用,而不能由结构或枚举采用。如果为了检查一致性而将协议标记为@objc,则只能将该协议应用于类类型


最简单的答案是:不要那样做。改用重载和约束,在编译时预先确定所有内容,而不是在运行时动态测试。运行时类型检查和编译时泛型就像牛排和冰激凌一样——两者都很好,但混合起来有点奇怪

考虑一下这样的情况:

protocol MyProtocol { }

struct MyStruct <T>  { let val: T }

func myFunc<T: MyProtocol>(s: MyStruct<T>) -> T? {
    return s.val
}

func myFunc<T>(s: MyStruct<T>) -> T? {
    return nil
}

struct S1: MyProtocol { }
struct S2 { }

let m1 = MyStruct(val: S1())
let m2 = MyStruct(val: S2())

myFunc(m1) // returns an instance of S1
myFunc(m2) // returns nil, because S2 doesn't implement MyProtocol
let conforms: Bool = (Controller.self as Any) is Protocol.Type

但是,老实说,您真的需要在泛型函数中这样做吗?如果您不确定某个对象的实际类型,更好的选择可能是预先确定该类型,而不是将其推迟到以后,然后在泛型函数中对其进行处理以找出原因。

有点晚,但您可以使用
as?
测试来测试某个对象是否响应协议。测试:

if let currentVC = myViewController as? MyCustomProtocol {
    // currentVC responds to the MyCustomProtocol protocol =]
}
编辑:稍微短一点:

if let _ = self as? MyProtocol {
    // match
}
使用防护装置:

guard let _ = self as? MyProtocol else {
    // doesn't match
    return
}

如果您想处理多个
T
类型的案例,也可以利用swift:

func myFunc<T>(s: MyStruct<T>) -> T? {
    switch s {
    case let sType as MyProtocol:
        // do MyProtocol specific stuff here, using sType
    default:
        //this does not conform to MyProtocol
    ...
    }
}
func myFunc(s:MyStruct)->T?{
开关s{
case let sType作为MyProtocol:
//使用sType在此处执行MyProtocol特定的内容
违约:
//这不符合MyProtocol
...
}
}

我必须说@Alex想检查
T
类型是否符合协议,而不是
s
。有些回答者看不清楚

检查
T
类型是否符合如下协议:

if let _ = T.self as? MyProtocol.Type {
    //  T conform MyProtocol
}


让conforms=T.self是我的协议。键入

现代答案如下:(Swift 5.1)

func-myFunc(s:MyStruct)->T?{    ... }

对于测试用例,我会像这样检查一致性:

protocol MyProtocol { }

struct MyStruct <T>  { let val: T }

func myFunc<T: MyProtocol>(s: MyStruct<T>) -> T? {
    return s.val
}

func myFunc<T>(s: MyStruct<T>) -> T? {
    return nil
}

struct S1: MyProtocol { }
struct S2 { }

let m1 = MyStruct(val: S1())
let m2 = MyStruct(val: S2())

myFunc(m1) // returns an instance of S1
myFunc(m2) // returns nil, because S2 doesn't implement MyProtocol
let conforms: Bool = (Controller.self as Any) is Protocol.Type


即使这样,我还是会犯同样的错误<代码>@objc protocol MyProtocol{}struct MyStruct{}func myFunc(s:MyStruct)->T?{let conforms=T.self is MyProtocol}@Alex,在检查协议一致性之前,您需要构造T类型的实例(如我所知),如果您需要than类型T必须仅为than符合MyProtocol的类型,您可以指定它:
func myFunc(…)->T?
+1,回答很好。特别喜欢“运行时类型检查和编译时泛型就像牛排和冰激凌——两者都很好,但混合它们有点奇怪。”是的……除了重载和约束无法完成工作的边缘情况。考虑一种实现协议的扩展方法,即代码> JSONECOCODYE/<代码>,它要求<代码> init(JSON:JSON)抛出。我们希望
Array
实现
JSONEncodable
,但前提是它的元素也是
JSONEncodable
。我们不能将继承子句与约束结合起来,因此必须在
init
的实现中使用某种类型的类型检查,如果
元素
不可
jsonecodable
,可能会抛出错误。遗憾的是,这在AFAICT看来是不可能的。我应该补充一点,上面的难题可以通过使用中间类型作为thunk来解决,但这是一个非常不雅观的解决方案。@GregoryHigley现在应该可以通过Swift 4.1中的条件一致性来解决()无论有没有像
这样的提示,你都可以构造
MyStruct
,并且它可以告诉你该做什么。对于尝试代码的其他人,Swift 4在第一个构造函数参数上需要一个
,如果MyProtocol是CaseIterable(具有关联类型的协议),该怎么办?它显示错误:“CaseIterable”只能用作泛型约束,因为它具有自身或关联的类型要求。这是最佳答案,因为它回答了原始问题“如何做:
let confidence=T.Self是MyProtocol
”。同意,这是该问题的最佳答案!这需要一个
T
的实例,但该问题询问泛型类型。因此,Carlos的答案更好:Carlos Chaguendo的答案应该是IMO接受的答案。这并没有回答问题。这并不是真的,它没有回答所问的问题,但它回答了我的问题??这是如何回答问题的?这也不能回答问题,因为它在实例中的测试符合协议,而不是直接符合类型。应该被接受为正确答案
if T.self is MyProtocol.Type {
    //  T conform MyProtocol
}
func myFunc < T: MyProtocol> (s: MyStruct<T>) -> T? {    ... }
let conforms: Bool = (Controller.self as Any) is Protocol.Type