对同一个变量调用 Swift 的 readline 两次会忽略第二次调用
Calling Swift's readline to the same variable twice ignores the second call
我正在从命令行读取用户输入,检查它是否是有效的文件路径,如果不是,则要求用户重试。
如果用户输入的是 nil
,则第一次应将其视为任何其他错误输入,让用户输入新值,但第二次输入 nil
,程序应该强制退出。
(我假设 nil
值是用户不会故意输入的值,所以如果它发生两次以上,我假设出现问题并退出程序以避免永无止境的循环要求新的输入。这可能是也可能不是一个好方法,但这不会影响问题。)
问题是 readLine()
在收到行尾输入(产生 nil
值)后第二次调用时不会要求用户输入. (行尾可以用^D输入。)
这意味着 readLine()
自动位于 returns nil
的函数,因为这是接收 readLine()
.[=34= 的变量的最新值]
问题
不管接收变量已经有什么值都不应该调用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)时,循环将按预期工作。
- 最初
askUserForWordList()
函数中的 path
被声明为常量 (let path = readLine(stripNewline: true)
) 但我将其更改为 var
因为它应该在每次函数被调用。但是,这并不影响程序的工作方式。
- 我尝试在调用
readLine()
之前在行中单独声明 path
,但没有任何区别。
- 我尝试完全跳过
path
变量,让 askUserForWordList()
函数 return 直接得到 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!
}
readLine()
returns nil
如果(且仅当)标准输入文件描述符已到达文件末尾。这发生在(例如)读取输入时
来自 tty,并且 Ctrl-D
("end-of-transmission character")作为一行中的第一个字符输入。
所有随后的readLine()
调用然后return nil
也是如此,没有
方式检测 "Ctrl-D was entered twice"。
换句话说,一旦标准输入处于文件结束状态
您无法再从中读取任何数据。如果您的程序需要
更多数据则只能报错,例如
guard let path = readLine(stripNewline: true) else {
throw InputError.UnexpectedEndOfFile
}
我正在从命令行读取用户输入,检查它是否是有效的文件路径,如果不是,则要求用户重试。
如果用户输入的是 nil
,则第一次应将其视为任何其他错误输入,让用户输入新值,但第二次输入 nil
,程序应该强制退出。
(我假设 nil
值是用户不会故意输入的值,所以如果它发生两次以上,我假设出现问题并退出程序以避免永无止境的循环要求新的输入。这可能是也可能不是一个好方法,但这不会影响问题。)
问题是 readLine()
在收到行尾输入(产生 nil
值)后第二次调用时不会要求用户输入. (行尾可以用^D输入。)
这意味着 readLine()
自动位于 returns nil
的函数,因为这是接收 readLine()
.[=34= 的变量的最新值]
问题
不管接收变量已经有什么值都不应该调用
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)时,循环将按预期工作。
- 最初
askUserForWordList()
函数中的path
被声明为常量 (let path = readLine(stripNewline: true)
) 但我将其更改为var
因为它应该在每次函数被调用。但是,这并不影响程序的工作方式。 - 我尝试在调用
readLine()
之前在行中单独声明path
,但没有任何区别。 - 我尝试完全跳过
path
变量,让askUserForWordList()
函数 return 直接得到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! }
readLine()
returns nil
如果(且仅当)标准输入文件描述符已到达文件末尾。这发生在(例如)读取输入时
来自 tty,并且 Ctrl-D
("end-of-transmission character")作为一行中的第一个字符输入。
所有随后的readLine()
调用然后return nil
也是如此,没有
方式检测 "Ctrl-D was entered twice"。
换句话说,一旦标准输入处于文件结束状态
您无法再从中读取任何数据。如果您的程序需要
更多数据则只能报错,例如
guard let path = readLine(stripNewline: true) else {
throw InputError.UnexpectedEndOfFile
}