clistdinscala
我在Scala中创建了一个控制台接口应用程序作为todo列表。我的数据访问层使用Slick 3,我的界面使用简单的StdIn方法。但是我在读台词方面有些困难。我的主菜单运行良好,而内部菜单有时运行异常。特别是,当我第一次输入命令时,我没有得到任何结果,只是再次显示相同的菜单。然后我输入任何命令并得到结果。如果我试着输入一些3d时间的命令,我的程序就会停止运行System.exit。 以下是我的界面代码:clistdinscala,scala,command-line-interface,stdin,slick,Scala,Command Line Interface,Stdin,Slick,我在Scala中创建了一个控制台接口应用程序作为todo列表。我的数据访问层使用Slick 3,我的界面使用简单的StdIn方法。但是我在读台词方面有些困难。我的主菜单运行良好,而内部菜单有时运行异常。特别是,当我第一次输入命令时,我没有得到任何结果,只是再次显示相同的菜单。然后我输入任何命令并得到结果。如果我试着输入一些3d时间的命令,我的程序就会停止运行System.exit。 以下是我的界面代码: object UserInterface { def displayMainMenu()
object UserInterface {
def displayMainMenu(): Unit ={
println("Main menu:" + " \n1 - Login" + "\n2 - Exit")
println("\nChoose the operation you want to perform:")
val inputMainMenu = readInt()
buildMainMenu(inputMainMenu)
}
def buildMainMenu(inputNumber: Int) = inputNumber match {
case 1 => enterSystem()
case 2 => System.exit(0)
case _ => println("Your input was wrong. Try again"); displayMainMenu()
}
def enterSystem(): Unit ={
println("Input you login, please:")
val inputLogin = readLine()
println("Input you password, please:")
val inputPassword = readLine()
val checkLogin = Await.result(DAO.checkUserLogin(inputLogin, inputPassword), Duration.Inf).toString
val userId = DAO.selectUserId(inputLogin)
def changeOutputs(checkLogin: String):Unit = checkLogin match {
case "true" => println("You have successfully entered"); displayInnerMenu(); buildMenu(userId)
case "false" => println("Your input for login or password is wrong. Please, try again"); displayMainMenu()
case _ => println("Your input is wrong"); displayMainMenu()
}
changeOutputs(checkLogin)
}
def buildMenu(userId: Long): Unit ={
def chooseOption(number: Int):Unit = number match {
case 1 => displayFinishedTasks(userId)
case 2 => displayUnfinishedTasks(userId)
case 3 => addTask(userId)
case 4 => deleteTask()
case 5 => markTaskAsFinished(userId)
case 6 => displayMainMenu()
case _ => println("Your input is wrong"); displayMainMenu()
}
val inputNum = displayInnerMenu()
chooseOption(inputNum)
}
def displayInnerMenu():Int ={
println("TODO List:" + "\n1 - Display finished tasks" + "\n2 - Display unfinished tasks"
+ "\n3 - Add task" + "\n4 - Delete task" + "\n5 - Mark task as finished" + "\n6 - Get back to the main menu")
println("\nChoose the operation you want to perform:")
val inputNum = readInt()
inputNum
}
def displayAllTasks(id: Long) = {
println()
println("User's tasks:\n" + Await.result(DAO.selectTasksByUser(id), Duration.Inf).toList.toString)
displayInnerMenu()
}
def displayFinishedTasks(id: Long) = {
println()
println("User's finished tasks:\n" + Await.result(DAO.selectFinishedTasks(id), Duration.Inf).toList.toString)
displayInnerMenu()
}
def displayUnfinishedTasks(id: Long) = {
println()
println("User's unfinished tasks:\n" + Await.result(DAO.selectUnfinishedTasks(id), Duration.Inf).toList.toString)
displayInnerMenu()
}
def addTask(id: Long) = {
println()
println("Input the task name you want to create, please:")
val taskName = readLine()
Await.result(DAO.addTask(taskName, id), Duration.Inf)
displayInnerMenu()
}
def deleteTask() = {
println()
println("Choose the task you want to delete, please:")
val taskId = readLong()
Await.result(DAO.deleteTask(Some(taskId)), Duration.Inf)
displayInnerMenu()
}
def markTaskAsFinished(id: Long) = {
println()
println("Choose the task you want to mark as finished, please:")
val taskId = readLong()
Await.result(DAO.finishTask(Some(taskId), id), Duration.Inf)
displayInnerMenu()
}
}
我想要的是某种无限循环,这样我可以根据需要多次执行命令或设置限制。那么,我可以在这段代码中引入哪些更改?我将非常感谢您的帮助 您的特别麻烦似乎来自以下事实:
changeOutputs
in
进入系统
调用显示内部菜单
,该菜单从输入中读取一个Int
,但对它没有任何用处。在调用displayInnerMenu
的大多数地方,您可能应该调用buildMenu
另外,您似乎应该提高调试技能。这是一项至关重要的技能,而且这段代码调试起来并不难
从更广泛的角度来看,这是一个复杂的话题,没有简单的最佳答案。但是肯定有不好的,不幸的是你的就是其中之一。代码中我最不喜欢的是菜单项标题和菜单项操作之间的代码大分隔。(只需想象在中间添加新的菜单项需要什么,或者创建一个更深的菜单,其中有一些在级别之间共享的项目。)所以我会重新编写大部分代码。与FP相比,我更喜欢OOP,我会这样做:
object UserInterface {
// should be non-generic for simplicity of the rest of the code
trait MenuAndStateNG {
def runMenu(): MenuAndStateNG
}
trait MenuItem[S] {
val name: String
def doAction(state: S, curMenu: MenuAndStateNG): MenuAndStateNG
}
case class Menu[S](header: String, items: Seq[MenuItem[S]]) {}
case class MenuAndState[S](menu: Menu[S], state: S) extends MenuAndStateNG {
def runMenu(): MenuAndStateNG = {
var inputNum: Int = -1
var isFirstRun = true
// we use 1-based indices in the menu
while (inputNum <= 0 || inputNum > menu.items.length) {
if (!isFirstRun) {
println("Your input was wrong. Try again")
}
isFirstRun = false
println(menu.header + ":")
println(menu.items.zipWithIndex.map({ case (item, index) => s"${index + 1} - ${item.name}" }).mkString("\n"))
println("Choose the operation you want to perform:")
inputNum = StdIn.readInt()
}
println()
val nextMenu = menu.items(inputNum - 1).doAction(state, this)
nextMenu
}
}
// most of menu items doesn't change current menu
// let's make it easier to implement
trait SimpleMenuItem[S] extends MenuItem[S] {
override def doAction(state: S, curMenu: MenuAndStateNG): MenuAndStateNG = {
doSimpleAction(state)
curMenu
}
def doSimpleAction(state: S): Unit
}
def start(): Unit = {
var curMenu: MenuAndStateNG = MenuAndState(mainMenu, ())
var isFirstRun = true
while (true) {
if (!isFirstRun) {
println
}
isFirstRun = false
curMenu = curMenu.runMenu()
}
}
private val loginItem = new MenuItem[Unit] {
override val name = "Login"
override def doAction(state: Unit, curMenu: MenuAndStateNG): MenuAndStateNG = {
println("Input you login, please:")
val inputLogin = StdIn.readLine()
println("Input you password, please:")
val inputPassword = StdIn.readLine()
val checkLogin = Await.result(DAO.checkUserLogin(inputLogin, inputPassword), Duration.Inf).toString
val userId = DAO.selectUserId(inputLogin)
checkLogin match {
case "true" =>
println("You have successfully entered")
MenuAndState(userMenu, userId)
case "false" =>
println("Your input for login or password is wrong. Please, try again")
curMenu
case _ =>
println("Your input is wrong")
curMenu
}
}
}
private val exitItem = new MenuItem[Unit] {
override val name = "Exit"
override def doAction(state: Unit, curMenu: MenuAndStateNG): MenuAndStateNG = {
System.exit(0)
null // null is bad but it doesn't matter by now
}
}
private val displayFinishedTasks = new SimpleMenuItem[Int] {
override val name: String = "Display finished tasks"
override def doSimpleAction(state: Int): Unit = {
println("User's finished tasks:\n" + Await.result(DAO.selectFinishedTasks(id), Duration.Inf).toList.toString)
}
}
private val displayUnfinishedTasks = new SimpleMenuItem[Int] {
override val name: String = "Display unfinished tasks"
override def doSimpleAction(state: Int): Unit = {
println("User's unfinished tasks:\n" + Await.result(DAO.selectUnfinishedTasks(id), Duration.Inf).toList.toString)
}
}
private val displayAllTasks = new SimpleMenuItem[Int] {
override val name: String = "Display all tasks"
override def doSimpleAction(state: Int): Unit = {
println("User's tasks:\n" + Await.result(DAO.selectTasksByUser(id), Duration.Inf).toList.toString)
}
}
private val addTask = new SimpleMenuItem[Int] {
override val name: String = "Add task"
override def doSimpleAction(state: Int): Unit = {
println("Input the task name you want to create, please:")
val taskName = readLine()
Await.result(DAO.addTask(taskName, id), Duration.Inf)
}
}
private val deleteTask = new SimpleMenuItem[Int] {
override val name: String = "Delete task"
override def doSimpleAction(state: Int): Unit = {
println("Choose the task you want to delete, please:")
val taskId = readLong()
Await.result(DAO.deleteTask(Some(taskId)), Duration.Inf)
}
}
private val markTaskFinished = new SimpleMenuItem[Int] {
override val name: String = "Mark task as finished"
override def doSimpleAction(state: Int): Unit = {
println("Choose the task you want to mark as finished, please:")
val taskId = readLong()
Await.result(DAO.finishTask(Some(taskId), id), Duration.Inf)
}
}
private val logoutTask = new MenuItem[Int] {
override val name = "Get back to the main menu"
override def doAction(state: Int, curMenu: MenuAndStateNG): MenuAndState[Unit] = {
MenuAndState(mainMenu, ())
}
}
val mainMenu: Menu[Unit] = Menu("Main menu", List(loginItem, exitItem))
val userMenu: Menu[Int] = Menu("User menu", List(
displayAllTasks,
displayFinishedTasks,
displayUnfinishedTasks,
addTask,
deleteTask,
markTaskFinished,
logoutTask))
}
对象用户界面{
//应为非泛型,以简化其余代码
性状MenuAndStateNG{
def runMenu():MenuAndStateNG
}
特征菜单项[S]{
val名称:String
def doAction(状态:S,当前菜单:菜单和状态):菜单和状态
}
案例类菜单[S](标题:字符串,项:Seq[MenuItem[S]]){}
案例类MenuAndState[S](菜单:菜单[S],状态:S)扩展了MenuAndStateNG{
def runMenu():MenuAndStateNG={
变量inputNum:Int=-1
var isFirstRun=true
//我们在菜单中使用基于1的索引
while(inputNum menu.items.length){
如果(!isFirstRun){
println(“您的输入错误,请重试”)
}
isFirstRun=false
println(menu.header+“:”)
println(menu.items.zipWithIndex.map({case(item,index)=>s“${index+1}-${item.name}”).mkString(“\n”))
println(“选择要执行的操作:”)
inputNum=StdIn.readInt()
}
println()
val nextMenu=menu.items(inputNum-1).doAction(状态,this)
下一个菜单
}
}
//大多数菜单项不会更改当前菜单
//让我们让它更容易实现
trait simplenumitem[S]扩展了MenuItem[S]{
覆盖def doAction(状态:S,curMenu:MenuAndStateNG):MenuAndStateNG={
行动(州)
curMenu
}
def操作(状态:S):单位
}
def start():单位={
变量curMenu:MenuAndStateNG=MenuAndState(主菜单,())
var isFirstRun=true
while(true){
如果(!isFirstRun){
普林顿
}
isFirstRun=false
curMenu=curMenu.runMenu()
}
}
private val loginItem=新菜单项[单位]{
覆盖val name=“登录”
覆盖def doAction(状态:单位,当前菜单:菜单和状态):菜单和状态={
println(“请输入您的登录名:”)
val inputLogin=StdIn.readLine()
println(“请输入您的密码:”)
val inputPassword=StdIn.readLine()
val checkLogin=Await.result(DAO.checkUserLogin(inputLogin,inputPassword),Duration.Inf).toString
val userId=DAO.selectUserId(inputLogin)
检查登录匹配{
大小写“true”=>
println(“您已成功输入”)
菜单和状态(用户菜单,用户ID)
大小写“false”=>
println(“您的登录或密码输入错误。请重试”)
curMenu
案例=>
println(“您的输入错误”)
curMenu
}
}
}
private val exitItem=新菜单项[单位]{
覆盖val name=“退出”
覆盖def doAction(状态:单位,当前菜单:菜单和状态):菜单和状态={
系统退出(0)
null//null很糟糕,但现在已经不重要了
}
}
private val displayFinishedTasks=新SimpleNuItem[Int]{
覆盖val名称:String=“显示已完成的任务”
覆盖操作(状态:Int):单位={
println(“用户完成的任务:\n”+wait.result(DAO.selectFinishedTasks(id),Duration.Inf)。toList.toString)
}
}
private val displayUnfinishedTasks=新SimpleNuItem[Int]{
覆盖val名称:String=“显示未完成的任务”
覆盖操作(状态:Int):单位={
println(“用户未完成的任务:\n”+wait.result(DAO.selectUnfinishedTasks(id),Duration.Inf)。toList.toString)
}
}
private val displayAllTasks=new simplenumitem[Int]{
覆盖val名称:String=“显示所有任务”
覆盖操作(状态:Int):单位={
println(“用户的任务:\n”+wait.result(DAO.selectTasksByUser(id),Duration.Inf).toList.toString)
}
}
private val addTask=new simplenumitem[Int]{
覆盖val名称:String=“添加任务”
覆盖操作(状态:Int):单位={
println(“请输入要创建的任务名称:”)
val taskName=readLine()
wait.result(DAO.addTask(taskName,id),Duration.Inf)
}
}
private val deleteTask=新SimpleNuitem[Int]{
覆盖val名称:String=“删除任务”
覆盖操作(状态:Int):单位={
println(“请选择要删除的任务:”)
val taskId=readLong