2014-10-20 81 views
0

我來自C++,我對Swift中的泛型函數有點困惑。Swift中的泛型函數

在C++中,我能做到這一點:

class Entity 
{ 
    template <typename T> 
    T *getComponent() 
    { 
     return (T *)(listComponent_[typeid(T).name()]); 
    } 
}; 

,我可以做到這一點,從獲取特定ComponentEntity

Entity().getComponent<LifeComponent>(); 

我想重現此斯威夫特,但我無法弄清楚如何實現它。

在Swift中,我必須爲我的函數定義一個參數來確定我的類型。

在斯威夫特:

class Entity 
{ 
    func get<T>() -> T 
    { 
     return ?? 
    } 
} 

我希望能夠做到:

Entity().get<LifeComponent>() 

你能幫助我嗎?

+3

[谷歌,先打:官方文檔(https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26 -XID_278)。 [谷歌,第三擊:教程](http://www.codingexplorer.com/generic-functions-in-swift/)。您不必「弄清楚」這一點:使用Google並閱讀文檔就足夠了。 – 2014-10-20 13:11:53

+0

我知道如何創建泛型函數,以及如何使用它。我只想知道是否有一種方法可以像C++中那樣在Swift中傳入一個類型。 – cappie013 2014-10-20 13:21:32

回答

0

這是儘可能接近你想要做的事情的精神。

在這種情況下,我們正在定義一個協議,告知Entity如何獲取組件的名稱。明確的使它比任何獲取變量的類型名稱或類的名稱的黑客更加可靠和清晰,所有這些都具有多種限制。請注意,如果組件都有一個共同的超類,或者即使它們都是所有的子類,這也可以大大簡化。使用協議方法可能是最好的方法,因爲實體中的東西,不管它們是什麼,都應該有一些共同的共享界面,否則你不知道你可以用它們做什麼。

// Mostly the Component protocol is needed so that we can create an 
// item with no arguments. 
protocol NamedComponent { 
    class var ComponentName : String { get } 
} 

// Make Int an allowable component 
extension Int : NamedComponent { 
    static let ComponentName = "Int" 
} 

extension String : NamedComponent { 
    static let ComponentName = "String" 
} 

// make a class a NamedComponent, note the different syntax between 
// adding a class constant to a class here and to a struct or base type 
// above 
class SomeComponent : NamedComponent { 
    class var ComponentName : String { get { return "SomeComponent" } } 
} 

class Entity { 
    // The component library 
    var components = [String:NamedComponent]() 

    // add a component to the library by class name 
    func register<T:NamedComponent>(value:T) { 
     components[T.ComponentName] = value 
    } 

    // Reference a component by class name 
    func get<T:NamedComponent>() -> T? { 
     return components[T.ComponentName] as? T 
    } 
} 

// Create the entity 
let entity = Entity() 

// Add a dummy component 
entity.register(45) 
entity.register("string") 
entity.register(SomeComponent()) 

// Fetch a dummy component 
let int : Int? = entity.get() 
println("\(int)") 

let str : String? = entity.get() 
println("\(str)") 

let comp : SomeComponent? = entity.get() 
println("\(comp)") 
0

你需要告訴編譯器它可以用T做什麼,否則它幾乎沒用。

Swift必須知道,在編譯時什麼你會傳遞到get()函數。它不會盲目地接受你提供的任何內存。編譯器必須被告知內存中會有什麼。

下面是描述如何使用泛型的斯威夫特,這應該回答你所有的問題的文檔:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html

另一種選擇是你可以使用的Objective-C甚至C++。

iOS和OS X的大多數軟件都是用Objective-C或C/C++編寫的。目前幾乎沒有任何東西是用Swift編寫的,而且這種語言還沒有完全可行的語言。主要編寫在Swift中的項目可以很好地與用Objective-C或C/C++編寫的代碼集成。

+0

「Swift在編譯時必須知道你要傳入get()函數的內容。」 'get()'函數不帶任何參數;沒有什麼是「傳入」的。 – newacct 2014-10-22 07:31:20

1

我不知道C++的語法,但也許你想要的是這樣的?

class Entity { 
    var list:[Any] = [] 

    func register(obj:Any) { 
     list.append(obj) 
    } 
    func getComponent<T>(type:T.Type) -> T? { 
     for obj in list { 
      if let instance = obj as? T { 
       return instance 
      } 
     } 
     return nil 
    } 
} 

let cls = Entity() 
cls.register(1) 
cls.register("This is a String") 
cls.register(UIView()) 
cls.register(1.01) 

cls.getComponent(String) // -> Optional("This is a String") 
0

只是偶然發現了同樣的問題。如何調用通用函數?

爲我找到了一個解決方案,也許它也適用於你。我有一些我想從字典中初始化的結構。我所有的結構都實現了一個協議DictionaryInitializable

struct MyStruct: DictionaryInitializable { 
    ... 
    init?(dictionary: [String: AnyObject]) { 
     ... 
    } 
} 

我也有以下方法解析器:

func parse<T: DictionaryInitializable>(dict: [String: AnyObject]) -> T? { 
    return T(dictionary: dict) 
} 

要使用該功能,你可以使用如下代碼:

let parsedStruct: MyStruct = parser.parse(dictionary) 

這工作在Xcode 7.3 Swift 2.2。在此之前從未測試過版本。