Я читаю пользовательский ввод из командной строки, проверяя, является ли он допустимым файловым путем, и если он не просит пользователя повторить попытку.Вызов строки чтения Swift для одной и той же переменной дважды игнорирует второй вызов
В случае ввода пользователем nil
его следует рассматривать как любой другой неправильный ввод в первый раз, позволяя пользователю вводить новое значение, но во второй раз, когда вводится nil
, программа должна принудительно завершить работу.
(Я предполагаю, что значение nil
- это то, что пользователь не будет вводить нарочно, поэтому, если это произойдет более двух раз, я предполагаю, что что-то пошло не так и вышло из программы, чтобы избежать бесконечного цикла, запрашивающего новый ввод. Это может быть или не быть хорошим способом сделать это, но это не влияет на вопрос.)
Проблема в том, что readLine()
не запрашивает ввод пользователя во второй раз, после того как он получил end-of-line input (который дает значение nil
). (End-линии могут быть введены с^D).
Это означает, что функция, где readLine()
находится автоматически возвращает nil
, потому что это последнее значение переменной, которая получит readLine()
.
Вопросы
не должны
readLine()
назвать независимо от того, какое значение получающее переменная уже имеет?Если да, то почему пользователь не запрашивает ввод, когда
nil
был введен один раз?
Это код:
import Foundation
/**
Ask the user to provide a word list file, check if the file exists. If it doesn't exist, ask the user again.
*/
func askUserForWordList() -> String? {
print("")
print("Please drag a word list file here (or enter its path manually), to use as basis for the statistics:")
var path = readLine(stripNewline: true) // THIS IS SKIPPED IF "PATH" IS ALREADY "NIL".
return path
}
/**
Check the user input // PROBABLY NOT RELEVANT FOR THIS QUESTION
*/
func fileExists(filePath: String) -> Bool {
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(filePath) {
return true
} else {
return false
}
}
/**
Get the file from the user and make sure it’s valid.
*/
func getFilePathFromUser() throws -> String {
enum inputError: ErrorType {
case TwoConsecutiveEndOfFiles
}
var correctFile = false
var path: String? = ""
var numberOfConsecutiveNilFiles = 0
repeat {
// Check that the user did not enter a nil-value (end-of-file) – if they did so two times in a row, terminate the program as this might be some kind of error (so that we don't get an infinite loop).
if numberOfConsecutiveNilFiles > 1 { // FIXME: entering ^D once is enough to end the program (it should require two ^D). Actually the problem seems to be in function "askUserForWordList()".
throw inputError.TwoConsecutiveEndOfFiles
}
path = askUserForWordList()
if path == nil {
numberOfConsecutiveNilFiles += 1
} else {
numberOfConsecutiveNilFiles = 0
correctFile = fileExists(path!)
if !correctFile {
print("")
print("Oops, I couldn't recognize that file path. Please try again.")
}
}
} while !correctFile
return path!
}
// This is where the actual execution starts
print("")
print("=== Welcome to \"Word Statistics\", command line version ===")
print("")
print("This program will give you some statistics for the list of words you provide.")
do {
let path = try getFilePathFromUser()
} catch {
print("Error: \(error)")
exit(-46) // Using closest error type from http://www.swiftview.com/tech/exitcodes.htm (which may not be standard at all. I could, however, not find any "standard" list of exit values).
}
Примечания
- При вводе любой другой недействительный путь (любая строка, даже пустой (просто нажмите Enter), петля работает по назначению.
- Первоначально
path
в функцииaskUserForWordList()
было объявлено как конста nt (let path = readLine(stripNewline: true)
), но я изменил его наvar
, так как он должен обновляться каждый раз, когда вызывается функция. Однако это не повлияло на работу программы. - Я пробовал объявить
path
отдельно на линии перед вызовомreadLine()
, что не имело значения. - Я попробовал пропустить переменную
path
полностью и позволить функцииaskUserForWordList()
вернуть результатreadLine()
(return readLine(stripNewline: true)
). Это не имело никакого значения. Я пропустил функцию
askUserForWordList()
и переместил код с запросом ввода пользователем в «основной» код функции «getFilePathFromUser()», но это ничего не изменило.Модифицированный код:
func getFilePathFromUser() throws -> String { enum inputError: ErrorType { case TwoConsecutiveEndOfFiles } var correctFile = false var path: String? = "" var numberOfConsecutiveNilFiles = 0 repeat { // Check that the user did not enter a nil-value (end-of-file) – if they did so two times in a row, terminate the program as this might be some kind of error (so that we don't get an infinite loop). if numberOfConsecutiveNilFiles > 1 { // FIXME: entering ^D once is enough to end the program (it should require two ^D). Actually the problem seems to be in function "askUserForWordList()". throw inputError.TwoConsecutiveEndOfFiles } // MODIFIED – This code was previously located in "askUserForWordList()" print("") print("Please drag a word list file here (or enter its path manually), to use as basis for the statistics:") path = readLine(stripNewline: true) // END OF MODIFICATION if path == nil { numberOfConsecutiveNilFiles += 1 } else { numberOfConsecutiveNilFiles = 0 correctFile = fileExists(path!) if !correctFile { print("") print("Oops, I couldn't recognize that file path. Please try again.") } } } while !correctFile return path! }
Что касается 'выхода (-46)', Swift коды выхода являются такими же, как и в C, так что только "стандартные" значения: 0 ('EXIT_SUCCESS') и 1 (' EXIT_FAILURE'). Если вы намерены выйти в любом случае, я бы предложил вместо этого использовать 'fatalError()', поскольку он выводит файл и номер строки начального сбоя, который помогает при отладке. – xoudini