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.slang module 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.slang implementing a; internal void f_b(); // Defines f_b in module `a`. public void publicFunc(); // m.slang module 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
参考资料
- shader-slang/slang: Making it easier to work with shaders (github.com)
- Modules and Access Control | slang