Lua重复require时单例实现问题:多次引入会创建多实例吗?
Great question! Let's break this down step by step.
Will there be two some-library instances?
No, there won't be. Lua's require function has a built-in caching mechanism that prevents modules from being executed multiple times. Here's exactly what happens when you run lua file2:
- When
file1callsrequire('wrapper'), Lua executes the wrapper module's code: it loadssome-library, creates an instance viasome_library.new(...), and stores the resultingwrappertable inpackage.loaded['wrapper']. - Later, when
file2callsrequire('wrapper'), Lua checks thepackage.loadedcache first. Since the wrapper module is already cached, it returns the existingwrappertable directly—it does not re-run the module code, sosome_library.new(...)is only called once.
By default, you'll only ever have one instance of some-library in this setup.
How to explicitly implement a singleton (for extra safety or flexibility)
While Lua's require caching already ensures a module-level singleton, you can make this behavior more explicit or add flexibility (like lazy initialization) with these approaches:
1. Explicitly check the module cache
Modify your wrapper module to directly leverage Lua's cache system, making the singleton behavior obvious:
-- Check if we're already loaded in the package cache local wrapper = package.loaded['wrapper'] if wrapper then return wrapper end wrapper = {} local some_library = require('some-library') wrapper._library = some_library.new(...) -- Manually set the cache entry to lock in the singleton package.loaded['wrapper'] = wrapper return wrapper
This guards against edge cases where someone might modify package.loaded accidentally, ensuring no duplicate instances are created.
2. Hide the instance in a closure
Encapsulate the instance in a local closure so it's completely hidden from external code, only exposing the methods you want to make public:
local some_library = require('some-library') -- The instance is a local variable, only accessible inside this module local instance = some_library.new(...) local wrapper = {} -- Example: Proxy methods from the instance to the wrapper function wrapper.perform_action(arg1, arg2) return instance:perform_action(arg1, arg2) end return wrapper
This makes the singleton truly immutable—external code can't modify or replace the instance, only interact with it via your defined methods.
3. Lazy initialization with a factory
If you need to initialize the instance with runtime parameters (not just when the module loads), use a factory function to manage the singleton:
local some_library = require('some-library') local instance = nil local wrapper = {} -- Factory method to get or create the instance on demand function wrapper.get_instance(...) if not instance then -- Initialize with arguments passed at runtime instance = some_library.new(...) end return instance end -- Optional: Automatically proxy wrapper method calls to the instance setmetatable(wrapper, { __index = function(_, method_name) local inst = wrapper.get_instance() return inst[method_name] end }) return wrapper
With this setup, you can delay instance creation until you have the necessary parameters, while still guaranteeing only one instance exists.
内容的提问来源于stack exchange,提问作者Kousha

