web-dev-qa-db-ja.com

Swiftでジェネリック型の名前(文字列)を取得します

タイプTのジェネリッククラスがあり、インスタンス化されたときにクラスに渡されたタイプの名前を取得したいと考えています。ここに例があります。

class MyClass<T> {
    func genericName() -> String {
        // Return the name of T.
    }
}

私は何時間も探し回っていましたが、これを行う方法を見つけることができません。誰かこれをまだ試しましたか?

どんな助けでも大歓迎です。

ありがとう

26
Rob

純粋なSwiftそれを達成する方法は不可能です。

可能な回避策は次のとおりです。

_class MyClass<T: AnyObject> {
    func genericName() -> String {
        let fullName: String = NSStringFromClass(T.self)
        let range = fullName.rangeOfString(".", options: .BackwardsSearch)
        if let range = range {
            return fullName.substringFromIndex(range.endIndex)
        } else {
            return fullName
        }
    }
}
_

制限は、クラスでのみ機能するという事実に依存しています。

これがジェネリック型の場合:

_class TestClass {}
_

NSStringFromClass()は、フルネーム(名前空間を含む)を返します。

_// Prints something like "__lldb_expr_186.TestClass" in playground
NSStringFromClass(TestClass.self)
_

これが、funcが_._文字の最後の出現を検索する理由です。

次のようにテストされます。

_var x = MyClass<TestClass>()
x.genericName() // Prints "TestClass"
_

PDATE Swift 3.

_func genericName() -> String {
    let fullName: String = NSStringFromClass(T.self)
    let range = fullName.range(of: ".")
    if let range = range {
        return fullName.substring(from: range.upperBound)
    }
    return fullName
}
_
12
Antonio

文字列補間を使用して、任意の型の名前を返すことができます。

class MyClass<T> {
    func genericName() -> String {
        return "\(T.self)"
    }
}

あなたはそれを遊び場で試すことができ、それは期待通りに機能します:

var someClass = MyClass<String>()
someClass.genericName() // Returns "Swift.String"
19
Bradley Hilton

String(describing: T.self) in Swift 3+

_var genericTypeName: String {
    return String(describing: T.self)
}
_

ジェネリック型内で、_T.self_またはtype(of: T.self)Tに変換して、型Stringの名前を取得します。 type(of:)は必要ないことがわかりましたが、他の場合にはTypeに関する他の詳細が削除されるため、注意する必要があります。

次の例は、構造体とクラス内のジェネリック型Tの名前を取得する方法を示しています。含まれている型の名前を取得するコードが含まれています。

クラスと構造体を含む例

_struct GenericStruct<T> {
    var value: T

    var genericTypeName: String {
        return String(describing: T.self)
    }

    var genericTypeDescription: String {
        return "Generic Type T: '\(genericTypeName)'"
    }

    var typeDescription: String {
        // type(of:) is necessary here to exclude the struct's properties from the string
        return "Type: '\(type(of: self))'"
    }
}

class GenericClass<T> {
    var value: T

    var genericTypeName: String {
        return String(describing: T.self)
    }

    var genericTypeDescription: String {
        return "Generic Type T: '\(genericTypeName)'"
    }

    var typeDescription: String {
        let typeName = String(describing: self)
        return "Type: '\(typeName)'"
    }

    init(value: T) {
        self.value = value
    }
}

enum TestEnum {
    case value1
    case value2
    case value3
}

let intGenericStruct: GenericStruct<Int> = GenericStruct(value: 1)
print(intGenericStruct.typeDescription)
print(intGenericStruct.genericTypeDescription)

let enumGenericStruct: GenericStruct<TestEnum> = GenericStruct(value: .value2)
print(enumGenericStruct.typeDescription)
print(enumGenericStruct.genericTypeDescription)

let intGenericClass: GenericClass<Int> = GenericClass(value: 1)
print(intGenericClass.typeDescription)
print(intGenericClass.genericTypeDescription)

let enumGenericClass: GenericClass<TestEnum> = GenericClass(value: .value2)
print(enumGenericClass.typeDescription)
print(enumGenericClass.genericTypeDescription)
_

コンソール出力

_/*
Type: 'GenericStruct<Int>'
Generic Type T: 'Int'

Type: 'GenericStruct<TestEnum>'
Generic Type T: 'TestEnum'

Type: 'GenericClass<Swift.Int>'
Generic Type T: 'Int'

Type: 'GenericClass<TestEnum>'
Generic Type T: 'TestEnum'
*/
_
14
Mobile Dan

誰かを助けるかもしれない別の可能な解決策:

遊び場

import Foundation

class ClassType<T> {

    static func name () -> String
    {
        return "\(T.self)".componentsSeparatedByString(".").last!
    }
}

class MyClass {

}

func testClassName(){

    let className = ClassType<MyClass>.name()
    print(className)
}

testClassName()
1
brduca

タイプパラメータが一般的な命名プロトコルを実装している場合は可能です。

以下の例では、プロトコルNamedにより、ジェネリック型がnameクラスプロパティを実装することが保証されます。

以下のIntで示されているように、後者はプロトコルに準拠するように拡張できるため、これはクラスと値タイプの両方で機能することに注意してください。

protocol Named {
    class var name: String { get }
}

class MyClass<T: Named> {
    func genericName() -> String {
        return T.name
    }
}

extension Int: Named {
    static var name: String { return "I am an Int" }
}

class Foo: Named {
    class var name: String { return "I am a Foo" }
}

enum Drink: Named {
    static var name: String { return "I am a Drink" }
}

MyClass<Int>().genericName()  // I am an Int
MyClass<Foo>().genericName()  // I am a Foo
MyClass<Drink>().genericName()  // I am a Drink
1
augustzf