本文介绍了Swift中的泛型 - “通用参数'T'无法推断出来的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从方法中返回符合 MyProtocol UIViewController ,所以我使用方法签名:

  func myMethod< T其中T:UIViewController,T:MyProtocol>() - > T {

首先我不明白:if myMethod 返回例如一个 MyViewController 必须签名,我必须强制转换它:

  class MyViewController:UIViewController,MyProtocol 

我不能简单地 return MyViewController() 但我需要像这样投射它:返回MyViewController()as! T - 为什么这是必要的?



第二件事:我该如何在某处使用此方法?我不能简单地说

  let x = myMethod()as? UIViewController 

当我得到错误时

 通用参数'T'无法推断

我该如何实现这样的事情?如果我将它转换为 MyViewController ,它可以工作,但我想避免这种情况。

编辑:例子

  class MyViewController:UIViewController,MyProtocol {
}

协议MyProtocol {
}

func myMethod< T>() - > T其中T:UIViewController,T:MyProtocol {
返回MyViewController()as! T //为什么演员是必要的?
}

好的,我确实得到了一部分,但为什么要转换为 T 有必要吗? MyViewController UIViewController 的子类,并且符合协议,所以不需要转换,对吧?

解决方案
  func myMethod< T其中T:UIViewController,T:MyProtocol>() - > T 

这个声明说:存在一个名为 myMethod ,这样 myMethod 返回一些特定的 T ,其中 T UIViewController MyProtocol 的子类型。这并不是说实际上 T 是什么类型,并且并不表示只有一个这样的 myMethod 。如果有许多类型都是 UIViewController 的子类并且符合 MyProtocol ,则可以有很多类型。这些类型中的每一个都创建了一个新版本的 myMethod (对于断言 myMethod 而言真的是一个新解决方案,例如一个函数确实存在)。



这不同于:

  func myMethod() - > UIViewController 

表示:函数 myMethod 返回任何子类型 UIViewController



Swift没有办法表达任何类型是UIViewController的子类并且是MyProtocol的子类型。您只能讨论符合该标准的特定类型。 Swift无法以这种方式组合类和协议;这只是当前语言的限制,而不是一个深层次的设计问题。


$ b $ < 问题。有许多函数满足您的 myMethod 声明。每个 T 您都可以插入符合规则的候选人。所以当你说 myMethod()时,编译器不知道你指的是哪一个特定的 T



(我打算扩大这个答案,以更少的类型理论提供它,更多的是你怎么用代码来做,但donnywals已经有了一个很好的版本。 )

*到您编辑的问题*

  func myMethod< T>() - > T其中T:UIViewController,T:MyProtocol {
返回MyViewController()as! T //为什么演员是必要的?
}

T 是一个特定类型由调用者决定。它不是符合任何类型,而是符合某些具体,具体的类型。考虑一下你所说的情况:

 让vc:SomeOtherViewController = myMethod()

在这种情况下, T SomeOtherViewController MyViewController 不是那种类型,所以你对作为!转换的操作很危险。


I'd like to return a UIViewController conforming to MyProtocol from a method, so I'm using the method signature:

func myMethod<T where T : UIViewController, T : MyProtocol>() -> T {

First thing I don't understand: if myMethod returns e.g. a MyViewController which has to following signature, I have to force cast it:

class MyViewController: UIViewController, MyProtocol

I cannot simply return MyViewController() but I need to cast it like this: return MyViewController() as! T - why is this necessary?

And the second thing: how can I use this method somewhere? I cannot simply say

let x = myMethod() as? UIViewController

as I get the error

Generic parameter 'T' could not be inferred

How can I achieve something like this? If I cast it to MyViewController it works, but I would like to avoid that of course.

EDIT: Example

class MyViewController : UIViewController, MyProtocol {
}

protocol MyProtocol {
}

func myMethod<T>() -> T where T : UIViewController, T : MyProtocol {
    return MyViewController() as! T // why is the cast necessary?
}

ok, I do get one part, but why is the cast to T necessary? MyViewController is a subclass of UIViewController and conforms to the protocol, so no cast should be necessary, right?

解决方案
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T

This declaration says: There exists a function called myMethod, such that myMethod returns some specific T where T is a subtype of UIViewController and also MyProtocol. This does not say what type T actually is, and it does not say that there is only one such myMethod. There can be many if there are many type that are both subclasses of UIViewController and conform to MyProtocol. Every one of those types creates a new version of myMethod (really a new solution to the assertion myMethod makes, that such a function does exist).

This is not the same thing as:

func myMethod() -> UIViewController

That says: The function myMethod returns any subtype of UIViewController.

There is no way in Swift to express "any type that is a subclass of UIViewController and is a subtype of MyProtocol." You can only discuss a specific type that meets that criterial. Swift can't combine classes and protocols this way; it's just a current limitation of the language, not a deep design issue.

The specific versus any is the issue. There are many functions that satisfy your myMethod declaration. Every T you can plug in that conforms to the rules would be a candidate. So when you say myMethod(), the compiler doesn't know which specific T you mean.

(I was going to expand this answer to provide it in less type-theory, more "how do you do it in code" terms, but donnywals already has an excellent version of that.)

* To your edited question *

func myMethod<T>() -> T where T : UIViewController, T : MyProtocol {
    return MyViewController() as! T // why is the cast necessary?
}

T is a specific type decided by the caller. It is not "any type that conforms" it is "some specific, concrete type that conforms." Consider the case that you called:

let vc: SomeOtherViewController = myMethod()

In this case, T is SomeOtherViewController. MyViewController is not that type, so what you're doing with the as! cast is dangerous.

这篇关于Swift中的泛型 - “通用参数'T'无法推断出来的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-25 18:32