tuple - type swift




Función genérica tomando un nombre de tipo en Swift (2)

Lo que probablemente necesite hacer es crear un protocolo que se parezca a esto:

protocol SomeProtocol {
    init()
    func someProtocolMethod()
}

Y luego agregue T.Type como parámetro en su método:

func f<T: SomeProtocol>(t: T.Type) -> T {
    return T()
}

Luego, suponiendo que tienes un tipo que se ajuste a SomeProtocol esta manera:

struct MyType: SomeProtocol {
    init() { }
    func someProtocolMethod() { }
}

A continuación, puede llamar a su función de esta manera:

f(MyType.self).someProtocolMethod()

Como otros han notado, esto parece una forma enrevesada de hacer lo que quieras. Si conoce el tipo, por ejemplo, puede escribir:

MyType().someProtocolMethod()

No hay necesidad de f .

En C #, es posible llamar a un método genérico especificando el tipo:

public T f<T>()
{
   return something as T
}

var x = f<string>()

Swift no le permite especializar un método genérico al llamarlo. El compilador quiere confiar en la inferencia de tipo, por lo que esto no es posible:

func f<T>() -> T? {
    return something as T?
}

let x = f<String>() // not allowed in Swift

Lo que necesito es una forma de pasar un tipo a una función y esa función devolver un objeto de ese tipo, usando genéricos

Esto funciona, pero no es una buena opción para lo que quiero hacer:

let x = f() as String?

EDITAR (ACLARACIÓN)

Probablemente no haya sido muy claro acerca de cuál es la pregunta en realidad, se trata de una sintaxis más simple para llamar a una función que devuelve un tipo determinado (de cualquier tipo).

Como ejemplo simple, digamos que tiene una matriz de Cualquiera y crea una función que devuelve el primer elemento de un tipo dado:

// returns the first element in the array of that type
func findFirst<T>(array: [Any]) -> T? {
    return array.filter() { $0 is T }.first as? T
}

Puede llamar a esta función de esta manera:

let array = [something,something,something,...]

let x = findFirst(array) as String?

Eso es bastante simple, pero ¿qué pasa si el tipo devuelto es algún protocolo con un método y desea llamar al método en el objeto devuelto?

(findFirst(array) as MyProtocol?)?.SomeMethodInMyProtocol()
(findFirst(array) as OtherProtocol?)?.SomeMethodInOtherProtocol()

Esa sintaxis es simplemente incómoda. En C # (que está tan fuertemente tipado como Swift), puedes hacer esto:

findFirst<MyProtocol>(array).SomeMethodInMyProtocol();

Lamentablemente, eso no es posible en Swift.

Entonces la pregunta es: ¿hay alguna manera de lograr esto con una sintaxis más limpia (menos incómoda)?


Desafortunadamente, no se puede definir explícitamente el tipo de una función genérica (usando la sintaxis <...> en ella). Sin embargo, puede proporcionar un metatipo genérico ( T.Type ) como argumento de la función para permitir que Swift infiera el tipo genérico de la función, como ha dicho Roman .

Para su ejemplo específico, querrá que su función se vea así:

func findFirst<T>(in array: [Any], ofType _: T.Type) -> T? {
    return array.lazy.flatMap{ $0 as? T }.first
}

Aquí estamos usando flatMap(_:) para obtener una secuencia de elementos que se lanzaron correctamente a T , y luego first para obtener el primer elemento de esa secuencia. También estamos usando lazy para poder dejar de evaluar los elementos después de encontrar el primero.

Ejemplo de uso:

protocol SomeProtocol {
    func doSomething()
}

protocol AnotherProtocol {
    func somethingElse()
}

extension String : SomeProtocol {
    func doSomething() {
        print("success:", self)
    }
}

let a: [Any] = [5, "str", 6.7]

// outputs "success: str", as the second element is castable to SomeProtocol.
findFirst(in: a, ofType: SomeProtocol.self)?.doSomething()

// doesn't output anything, as none of the elements conform to AnotherProtocol.
findFirst(in: a, ofType: AnotherProtocol.self)?.somethingElse()

Tenga en cuenta que debe usar .self para hacer referencia al tipo de meta tipo de un tipo específico (en este caso, SomeProtocol ). Tal vez no es una mancha como la sintaxis que estabas buscando, pero creo que es tan buena como la que obtendrás.

Aunque vale la pena señalar en este caso que la función estaría mejor ubicada en una extensión de Sequence :

extension Sequence {
    func first<T>(ofType _: T.Type) -> T? {
        return lazy.flatMap{ $0 as? T }.first
    }
}

let a: [Any] = [5, "str", 6.7]

print(a.first(ofType: Double.self) as Any) // Optional(6.7000000000000002)




swift2