学会阅读源码

当你遇到一个问题,你会如何解决?

是在聊天群组里提问,然后被插科打诨,忘记自己的目标?

还是自食其力,选择面向搜索引擎,费九牛二虎之力解决?

自食其力是好事,然而面对开源项目时,直奔它的文档或者源代码是个缩小范围的好主意。

例子一

Linux 课上老师提到了 umask ,它是创建文件和文件夹时需要额外减去的权限值,在 Unix 下为 022(WSL 为 000)课后有同学提出,按照老师的方法并不能得出答案。

那么正确的计算是什么呢?答案在 linux 源码中:

// snippet from dir.c 
if (!fc->dont_mask)
        mode &= ~current_umask();
// snippet from fs_struct.c
int current_umask(void)
{
    return current->fs->umask;
}

从代码可以看出,mode 是 &~umask 得到的。

例子2

Wox 是一个 Windows 下的启动器,用户可以使用 Python 来为其编写插件。

由于 Wox 属于相对小众的应用,所以网上编写插件的例子不多。Python 开发的插件其实需要利用到 Wox 提供的几个接口,并且它们没有写在文档里面。

这时需要通过阅读 Wox.py 来了解实现:

# snippet from Wox.py
class Wox(object):
    """
    Wox python plugin base
    """

    def __init__(self):
        rpc_request = json.loads(sys.argv[1])
        # proxy is not working now
        self.proxy = rpc_request.get("proxy",{})
        request_method_name = rpc_request.get("method")
        request_parameters = rpc_request.get("parameters")
        methods = inspect.getmembers(self, predicate=inspect.ismethod)

        request_method = dict(methods)[request_method_name]
        results = request_method(*request_parameters)

        if request_method_name == "query" or request_method_name == "context_menu":
            print(json.dumps({"result": results}))

从 Wox.py 的 Wox 类可以了解到是 rpc 请求,进一步查看 C# 代码检查提供的接口:

namespace Wox.Plugin
{
    /// <summary>
    /// Public APIs that plugin can use
    /// </summary>
    public interface IPublicAPI
    {
        /// <summary>
        /// Push result to query box
        /// </summary>
        /// <param name="query"></param>
        /// <param name="plugin"></param>
        /// <param name="results"></param>
        [Obsolete("This method will be removed in Wox 1.3")]
        void PushResults(Query query, PluginMetadata plugin, List<Result> results);

        /// <summary>
        /// Change Wox query
        /// </summary>
        /// <param name="query">query text</param>
        /// <param name="requery">
        /// force requery By default, Wox will not fire query if your query is same with existing one. 
        /// Set this to true to force Wox requerying
        /// </param>
        void ChangeQuery(string query, bool requery = false);

        /// <summary>
        /// Just change the query text, this won't raise search
        /// </summary>
        /// <param name="query"></param>
        [Obsolete]
        void ChangeQueryText(string query, bool selectAll = false);

        /// <summary>
        /// Close Wox
        /// </summary>
        [Obsolete]
        void CloseApp();

        /// <summary>
        /// Restart Wox
        /// </summary>
        void RestarApp();

        /// <summary>
        /// Hide Wox
        /// </summary>
        [Obsolete]
        void HideApp();

        /// <summary>
        /// Show Wox
        /// </summary>
        [Obsolete]
        void ShowApp();

        /// <summary>
        /// Show message box
        /// </summary>
        /// <param name="title">Message title</param>
        /// <param name="subTitle">Message subtitle</param>
        /// <param name="iconPath">Message icon path (relative path to your plugin folder)</param>
        void ShowMsg(string title, string subTitle = "", string iconPath = "");

        /// <summary>
        /// Open setting dialog
        /// </summary>
        void OpenSettingDialog();

        /// <summary>
        /// Show loading animation
        /// </summary>
        [Obsolete("automatically start")]
        void StartLoadingBar();

        /// <summary>
        /// Stop loading animation
        /// </summary>
        [Obsolete("automatically stop")]
        void StopLoadingBar();

        /// <summary>
        /// Install Wox plugin
        /// </summary>
        /// <param name="path">Plugin path (ends with .wox)</param>
        void InstallPlugin(string path);

        /// <summary>
        /// Get translation of current language
        /// You need to implement IPluginI18n if you want to support multiple languages for your plugin
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        string GetTranslation(string key);

        /// <summary>
        /// Get all loaded plugins 
        /// </summary>
        /// <returns></returns>
        List<PluginPair> GetAllPlugins();

        /// <summary>
        /// Fired after global keyboard events
        /// if you want to hook something like Ctrl+R, you should use this event
        /// </summary>
        event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent;
    }
}

因此,除了使用好搜索引擎,学会阅读源码也是一个开发人员必备的本领。