тот же индекс, при построении его с двумя отдельными строками он работает нормально, при построении с одной строкой кода, я получаю ошибку, почему? - PullRequest
0 голосов
/ 17 января 2020

Я добавил две картинки своего кода, которые объясняют оба сценария: в первом сценарии индекс работает точно так, как он должен работать, с двумя строками кода

в сценарии второстепенного кода: оцените так же, как две строки, но по какой-то причине я получаю сообщение об ошибке

Можете ли вы помочь мне выяснить, ПОЧЕМУ?

рабочее изображение: рабочее изображение

изображение ошибки: изображение ошибки

полный код:

class SomeClass {

    var dic = Dictionary<String,(()->String) -> String>()

    subscript(_ s:String) -> (()->String) -> String {

        get{
            return dic[s]!
        }set{
            dic[s] = newValue
        }


    }


}


func createClass(_ s:String) -> SomeClass {

    func foo(_ str:()->String) ->String {
        return str() + " AND " + "Two"
    }
    let sc = SomeClass()
    sc["0"] = foo

    return sc

}


// WORKING TWO LINES

let someClass  = createClass("someStr")["0"]
let str = someClass{"One"} // everything work fine, no errors // prints 'One AND Two'



// ERROR ONE LINE

let str  = createClass("someStr")["0"]{"One"}



// WHY?

Ответы [ 2 ]

1 голос
/ 17 января 2020

Вам нужно поставить скобки вокруг createClass("someStr")["0"], потому что он пытается оценить ["0"]{"One"} до , он оценивает createClass("someStr") с нижним индексом. И даже когда вы сделаете это изменение, вы получите ошибку компиляции, потому что вы объявили переменную str дважды.

Иногда просто (не говоря уже о более ясном) иметь два отдельных оператора вместо попытки быть умным.

var str = "Hello, playground"

class SomeClass {
    var dic = Dictionary<String,(()->String) -> String>()
    subscript(_ s:String) -> (()->String) -> String {
        get{
            return dic[s]!
        }set{
            dic[s] = newValue
        }
    }
}
func createClass(_ s:String) -> SomeClass {
    func foo(_ str:()->String) ->String {
        return str() + " AND " + "Two"
    }
    let sc = SomeClass()
    sc["0"] = foo
    return sc
}

str = (createClass("someStr")["0"]){"One"}
print(str) // One AND Two
0 голосов
/ 19 января 2020

Ваш пример:

let str = createClass("someStr")["0"]{"One"}

использует синтаксис трейлинг-закрытия .

Синтаксис трейлинг-закрытия работает с включением трейлинг-замыкания как дополнительный параметр к вызову функции. Подписание массива на самом деле является вызовом функции изнутри (функции, называемой subscript), и Swift пытается передать это замыкание в качестве второго параметра для вызова подписки, что объясняет ошибка:

Невозможно указать значение типа SomeClass с аргументом типа (String, () -> String).

Другими словами, вы не можете передать оба "0" и закрытие {"One"} для функции подписки.


Существует как минимум 3 способа исправить это и все же поместить его в одну строку:

Опция 1: используйте явный вызов для передачи замыкания вместо использования синтаксиса конечного замыкания

Оберните замыкание в (), чтобы сделать вызов явным:

let str1 = createClass("someStr")["0"]({"One"})
print(str1)

Вариант 2: обернуть createClass("someStr")["0"] в скобки

Это позволяет Swift знать, что подписка получает только "0" в качестве параметра и позволяет синтаксису замыкания замыкания работать должным образом:

let str2 = (createClass("someStr")["0"]){"One"}
print(str2)

Вариант 3: Добавить .self к результату До синтаксиса завершающего замыкания:

Это снова завершает вызов по подписке и позволяет избежать путаницы.

let str3 = createClass("someStr")["0"].self {"One"}
print(str3)

Лично я бы выбрал Вариант 1 , потому что синтаксис завершающего замыкания является ненужным syntacti c сахар, который здесь явно не работает.


Решение задачи

В комментарии, которые я спросил:

Я согласен, что синтаксис конечного замыкания, скорее всего, является ошибкой, которую они могли бы исправить, но я не понимаю, почему вы настаиваете на использовании здесь синтаксиса конечного замыкания. Что такого нежелательного в том, чтобы обернуть замыкание в (), чтобы сделать вызов явным, даже если это просто обход ошибки в Swift?

Вы ответили:

причина настаивать на том, что я пытаюсь решить проблему. на самом деле, эта функция, которая возвращает замыкание, является только одной из сторон, она выглядит следующим образом С помощью операции индексации, хитрость заключается в том, чтобы спроектировать класс, который берет замыкание с помощью операции индексации:

class SomeClass {
    subscript(_ s: String, closure: () -> String) -> String {
        return String(closure().reversed())
    }
}

func foo(_ str: String) -> SomeClass {
    return SomeClass()
}

func Challenge() {
    // Do not edit below this line
    XCTAssertEqual(foo("str1")["str2"]{ "654321" }, "123456")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...