如何用R语言闭包为5个玩家实现计时器及相关函数?解决代码报错
问题分析与解决方案
首先,你遇到的Error: attempt to apply non-function错误,根源在于定义StopWatch函数时,list()里的内容是赋值表达式的结果,而非函数本身。比如strt<-function(Name = "name") Start <<- Sys.time()这行代码,执行后返回的是赋值后的函数,但你在list里的写法其实是把赋值操作的结果(函数)作为元素,语法逻辑有误;另外你误用了全局赋值<<-,这会导致多个玩家的时间互相覆盖,完全违背了闭包的封装性。
接下来我们重新实现支持5位玩家的计时器闭包,完整满足你需要的四个功能:
完整实现代码
StopWatch <- function() { # 内部环境存储玩家数据:每个玩家包含start_time和end_time players <- list() # 1. 开始计时函数:记录指定玩家的开始时间,最多支持5位玩家 start_timer <- function(player_name) { if (length(players) >= 5) { stop("最多支持5位玩家,请先结束已有玩家的计时") } if (player_name %in% names(players)) { warning(paste("玩家", player_name, "已经开始计时,将覆盖之前的开始时间")) } players[[player_name]] <- list(start_time = Sys.time(), end_time = NULL) invisible() } # 2. 结束计时函数:记录指定玩家的结束时间 stop_timer <- function(player_name) { if (!(player_name %in% names(players))) { stop(paste("玩家", player_name, "未开始计时")) } if (!is.null(players[[player_name]]$end_time)) { warning(paste("玩家", player_name, "已经结束计时,将覆盖之前的结束时间")) } players[[player_name]]$end_time <- Sys.time() invisible() } # 3. 获取单个玩家的时长 get_duration <- function(player_name) { if (!(player_name %in% names(players))) { stop(paste("玩家", player_name, "不存在")) } player_data <- players[[player_name]] if (is.null(player_data$end_time)) { stop(paste("玩家", player_name, "尚未结束计时")) } duration <- player_data$end_time - player_data$start_time cat(paste("玩家", player_name, "的时长:"), duration, "\n") return(duration) } # 4. 按降序显示所有已结束计时玩家的时长 show_results_desc <- function() { # 筛选出已结束计时的玩家 finished_players <- Filter(function(x) !is.null(x$end_time), players) if (length(finished_players) == 0) { cat("暂无已结束计时的玩家\n") return(invisible(NULL)) } # 计算每个玩家的时长 durations <- sapply(finished_players, function(x) x$end_time - x$start_time) # 按降序排序 sorted_durations <- sort(durations, decreasing = TRUE) # 打印结果 cat("玩家时长排名(降序):\n") for (i in seq_along(sorted_durations)) { cat(paste0(i, ". ", names(sorted_durations)[i], ": ", sorted_durations[i], "\n")) } return(invisible(sorted_durations)) } # 返回包含四个函数的列表 list( start = start_timer, stop = stop_timer, get_duration = get_duration, show_results = show_results_desc ) }
代码解释与使用示例
核心改进点
- 用闭包内部的
players列表存储每个玩家的时间数据,避免全局变量污染,保证数据的封装性 - 每个函数都是命名的,调用时逻辑更清晰(比如
w$start("player1")) - 增加了边界检查:限制最多5位玩家、检查玩家是否存在、是否已开始/结束计时,避免无效操作
- 完整实现了你要求的四个独立函数
使用示例
# 创建计时器实例 w <- StopWatch() # 开始玩家1的计时 w$start("player1") # 模拟耗时操作(这里用Sys.sleep代替你的sleep_for_a_minute) Sys.sleep(2) # 结束玩家1的计时 w$stop("player1") # 开始玩家2的计时 w$start("player2") Sys.sleep(1) w$stop("player2") # 获取玩家1的时长 w$get_duration("player1") # 按降序显示所有已结束玩家的时长 w$show_results()
运行结果示例
玩家 player1 的时长: Time difference of 2.001 secs 玩家时长排名(降序): 1. player1: Time difference of 2.001 secs 2. player2: Time difference of 1.000 secs
内容的提问来源于stack exchange,提问作者New_to_ML
相关产品推荐
相关产品推荐

