信息
· 文章中可能会出现一些错误,希望大佬们可以在评论区指出;
03-模块和访问控制
已道心破碎,以后就挑自己觉得重要的抄吧。感觉还不一定能用到我的OpenGL项目上,唉。
本篇将看看Slang中的模块系统,比头文件#include更高效。
模块与访问控制
Slang尽管支持预处理器#include,但仍推荐使用更新的模块系统。
定义模块
Slang中的模块可由一个或多个文件组成,一个模块必须有一个能用于识别它的文件,定义如下:
// scene.slang
module scene;
// ...
如果在其他文件中实现了该模块,需要使用__include语句来引入:
// scene.slang
module scene;
__include "scene-helpers";
// scene-helpers.slang
implementing scene;
// ...
其中,__include和#include不同:
- 预处理器阶段对
__include包含的文件和它本身互不可见。例如scene.slang中#define的东西在scene-helpers.slang中不可见,反之亦然。 - 不论
__include多少次,一个文件只会被包含在对应模块一次。 - 不论
__include的顺序,同一模块的所有文件可访问同一模块中定义的其他实体。
__include的样式主要有两种,通过一般标识符或字符串字面量:
// `file_name` is translated to "file-name".
__include dir.file_name;
__include "dir/file-name.slang";
__include "dir/file-name";
导入模块
可以用import关键字通过模块名导入另一个模块:
// MyShader.slang
import YourLibrary;
其中,导入的模块文件名中必须有对应的模块声明。
访问控制
Slang支持模块成员(变量、方法)的访问控制,通过三个关键字:
-
public:可以访问任何地方,不论是来自不同的类型、文件或模块。 -
private:只能由同类型的其他符号访问。struct MyType{private int member;int f() { member = 5; } // OK.struct ChildType{int g(MyType t){return t.member; // OK.}}}void outerFunc(MyType t){// Error, `member` is not visible here.t.member = 2;} -
internal:只能由同模块的内容访问。// a.slangmodule a;__include b;public struct PS{internal int internalMember;public int publicMember;}internal void f() { f_b(); } // OK, f_b defined in the same module.// b.slangimplementing a;internal void f_b(); // Defines f_b in module `a`.public void publicFunc();// m.slangmodule m;import a;void main(){f(); // Error, f is not visible here.publicFunc(); // OK.PS p; // OK.p.internalMember = 1; // Error, internalMember is not visible.p.publicMember = 1; // OK.}
如果没有专门设置,默认的访问权限是internal。但interface中的成员除外,它们的可见性默认是接口本身。
文件结构建议
顶层文件夹中包含一些可能被用户代码包含的模块,模块具体的实现细节则放入对应模块名的文件夹中。
Project
main.slang
materials.slang
materials
materialA.slang
materialB.slang
math.slang
utils.slang
utils
accumulators.slang
fill.slang
tonemap.slang