Here's another, simple alternative that doesn't require
recentf. Hooking the first function into
kill-buffer-hook will push the filename associated with the buffer onto a list. (Note that, if you kill a buffer that's not visiting a file, it's gone for good.) The latter function pops that file off of the list and visits it:
(defvar killed-file-list nil
"List of recently killed files.")
(defun add-file-to-killed-file-list ()
"If buffer is associated with a file name, add that file to the
`killed-file-list' when killing the buffer."
(push buffer-file-name killed-file-list)))
(add-hook 'kill-buffer-hook #'add-file-to-killed-file-list)
(defun reopen-killed-file ()
"Reopen the most recently killed file, if one exists."
(find-file (pop killed-file-list))))
killed-file-list is a list, so you could, for example, write a more intricate function to cycle through that list, rather than the simple one described here: it's up to you how much you want to do with it.
EDIT: sorry, I missed the last provision in your Q about wanting a list of files from which to choose. The following function is slightly fancier than the version above insofar as it uses
completing-read to let you specify which of the killed files you want. If you're using something like
ido, it'll let you cycle through all of the files you've killed in the current session, defaulting to the most recent. Note that it presumes that you've already required
(defun reopen-killed-file-fancy ()
"Pick a file to revisit from a list of files killed during this
(let ((file (completing-read "Reopen killed file: " killed-file-list
nil nil nil nil (car killed-file-list))))
(setq killed-file-list (cl-delete file killed-file-list :test #'equal))
(error "No recently-killed files to reopen")))