Как использовать параметр типа в typealias?

Я хочу использовать typealias для функции, которая используется в универсальном классе. Один из параметров функции использует универсальный тип класса. Это упрощенный пример:

class Bar {}

// no typealias - works
class TestGeneric<T: Bar> {
    let myFunc: (T) -> String

    init(myFunc: (T) -> String) {
        self.myFunc = myFunc
    }
}

let myFunc: (Bar) -> String = {(bar: Bar) in
    return "hello"
}

let test = TestGeneric<Bar>(myFunc: myFunc)
println(test.myFunc(Bar()))

// typealias - doesn't compile
class TestTypealias<T: Bar> {
    typealias MyFuncGeneric = (T) -> String

    let myFunc: MyFuncGeneric

    init(myFunc: MyFuncGeneric) {
        self.myFunc = myFunc
    }
}

let myFunc2: TestTypealias.MyFuncGeneric = {(bar: Bar) in
    return "hello"
}

let test2 = TestTypealias<Bar>(myFunc: myFunc2) // Error: Cannot invoke initializer for type 'TestTypealias<Bar>' with an argument list of type '(myFunc: T -> String)'
println(test2.myFunc(Bar()))

Есть ли способ решить эту проблему? Или мне нужно отказаться от typealias при использовании дженериков? В реальном коде у меня много параметров, и мне действительно нужен псевдоним...

(Свифт 1.2)


person User    schedule 28.04.2015    source источник


Ответы (2)


Написав

class TestGeneric<T: Bar> 

все, что вы действительно сделали, это универсально определили T как тип Bar при использовании внутри метода, поэтому вы можете написать это:

func myFunc(aValue:T) {

}

вместо этого:

func myFunc<T: Bar>(aValue:T) {

    }

каждый раз, когда вы хотите определить T как тип Bar.

Если вы хотите, чтобы сам класс был общим, вы используете только <T>, например: class TestGeneric<T> и тип определяется при инициализации.

class Bar {}

// no typealias - works
class TestGeneric<T> {
    let myFunc: (T) -> String

    init(myFunc: (T) -> String) {
        self.myFunc = myFunc
    }
}

let myFunc: Bar -> String = {(bar: Bar) in
    return "hello"
}

let test = TestGeneric<Bar>(myFunc: myFunc)
println(test.myFunc(Bar()))

// typealias - doesn't compile
class TestTypealias<T> {
    typealias MyFuncGeneric = T -> String
    func myFunc(aValue:T) {

    }
    let myFunc: MyFuncGeneric

    init(myFunc: MyFuncGeneric) {

        self.myFunc = myFunc
    }
}

let myFunc2: TestTypealias<Bar>.MyFuncGeneric = {(bar: Bar) in
    return "hello"
}

let test2 = TestTypealias<Bar>(myFunc: myFunc2)   
println(test2.myFunc(Bar()))
person sketchyTech    schedule 28.04.2015
comment
Мне нужно, чтобы класс был универсальным и ограничивал тип класса Bar (isA), поэтому я использую <T: Bar>. Чего мне не хватало, так это этой мелочи: объявить функцию как тип TestTypealias<Bar>.MyFuncGeneric вместо TestTypealias.MyFuncGeneric. Это также объясняет, почему моя упрощенная версия кода Грегзо работает, он просто не указал тип, и компилятор правильно его выводит. Спасибо! - person User; 28.04.2015

Это компилируется и ведет себя так, как ожидалось:

class Test< T >
{
    typealias GenFunc = ( thing: T ) -> Void

    let thing : T

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

    func ExecuteFunc( genFunc: GenFunc )
    {
        genFunc( thing: self.thing )
    }
}

Использовать:

let t = Test( thing: "blah" )

t.ExecuteFunc()
{ ( thing: String ) -> Void in
    println( thing )
}
person Gregzo    schedule 28.04.2015
comment
Я сократил ваш пример до наименьшего отличия от моего и обнаружил, что причиной ошибки компилятора является объявление типа функции! поэтому, если я напишу let myFunc2 = {(bar: Bar) in return "hello" } вместо let myFunc2: TestTypealias.MyFuncGeneric = {(bar: Bar) in return "hello" }, он скомпилируется... - person User; 28.04.2015