Verse Wiki — 写给 UE6 时代的 Verse 互动手册
拓展 · EXTRA

读写分离的变量权限:var<private> Ammo<public>

刚学会 var,马上就能用上的工程化升级:Verse 允许对一个类成员变量分别控制「谁能改」和「谁能读」。两个说明符各管一头,不写 getter 就能拿到只读属性。

一、问题:想让别人看,不想让别人改

做一个武器架设备,里面有个 var Ammo:int 记弹药数。别的代码经常需要它——UI 要显示剩余弹药,规则逻辑要判断能不能开火。但你绝对不想让别的代码随手 set 它:弹药数只应该由武器架自己在装填、射击时修改。一旦谁都能改,某天弹药凭空变成 999,你要在整个项目里大海捞针找那行肇事的 set。

做一个武器架设备,里面有个 var Ammo:int 记弹药数。别的蓝图经常需要它——UI 要显示剩余弹药,规则逻辑要判断能不能开火。但你绝对不想让别人随手接个 Set 节点改它:弹药数只应该由武器架自己在装填、射击时改。一旦谁都能改,某天弹药凭空变成 999,你就得在整个项目里大海捞针,找出那根肇事的 Set 连线。

传统面向对象语言的标准答案是:把字段设成 private,再写一个公开的 getter 函数。能用,但每个字段配一个样板函数,写多了很烦。Verse 的答案优雅得多——因为它把「读」和「写」看成两种独立的权限。

很多语言的标准答案是:把变量设成 private,再专门写一个公开的「读取函数」(getter)放出去给别人读。能用,但每个变量都要配一个这样的样板函数,写多了很烦。Verse 的答案优雅得多——因为它把「读」和「写」看成两种各自独立的权限。

二、语法:两个说明符,各管一头

规则一句话:写在 var 关键字上的说明符控制赋值权限(谁能 set),写在标识符(变量名)上的说明符控制读取权限(谁能读)。于是可以这样声明:

规则一句话:挂在 var 上的那个尖括号设置管「写」权限(谁能接 Set),挂在变量名上的那个尖括号设置管「读」权限(谁能读它的值)。于是可以这样声明:

weapon_rack.verse
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/Diagnostics }

weapon_rack := class:

    # 名字上的说明符管「读」:public = 谁都能读
    # var 上的说明符管「写」:private = 只有本类能 set
    var<private> Ammo<public>:int = 10

    Reload<public>():void =
        set Ammo = 30

拆开看:Ammo<public> 表示任何代码都可以读它的值——拿到一个 Rack:weapon_rack 之后,写 Print("{Rack.Ammo}") 没有任何障碍;而 var<private> 表示只有 weapon_rack 类自己的代码能 set 它——外部谁写 set Rack.Ammo = 999,编译器当场拒绝。想改弹药?请走类自己提供的 Reload() 正门。

读图翻译:Ammo<public> 表示任何蓝图都能读它的值——拿到一个 Rack:weapon_rack 之后,用 Print String 打 Rack.Ammo 毫无障碍;而 var<private> 表示只有 weapon_rack 自己内部的节点能给它接 Set——外部谁想接 set Rack.Ammo = 999,一按 Compile 当场被拒。想改弹药?请走这个类自己开的正门 Reload() 函数。

这相当于免费获得了只读属性:对外是橱窗里的展品,看得见摸不着;对内还是自家的背包格子,该 set 就 set。把写权限放宽一档也常见:var<protected> Ammo<public>:int = 10,子类也获准修改,适合做「基类定规则、子类做变体」的设备家族。

这相当于免费拿到一个「只读变量」:对外是橱窗里的展品,看得见摸不着;对内还是自家的背包格子,想接 Set 就接 Set。把写权限放宽一档也很常见:var<protected> Ammo<public>:int = 10,连子蓝图也获准改,适合做「基类定规则、子类做变体」的设备家族。

三、四档权限速查

读和写两个位置上,可用的访问说明符是同一套:

读和写这两个位置,能用的访问设置(说明符)是同一套:

说明符 谁能访问
<public> 任何地方
<internal>(默认) 同一模块内
<protected> 本类与它的子类
<private> 只有本类

注意默认值:什么都不写时,访问级别是 <internal>——模块内可见,而不是全局公开。这也解释了为什么小项目里「不写说明符也一切正常」:代码都在同一个模块里,internal 足够用;等项目拆成多个模块,权限问题才会浮出水面,而那时你已经会这一招了。

注意默认值:什么都不写时,访问级别就是 <internal>——同一个模块(资产文件夹)里可见,而不是全局公开。这也解释了为什么小项目里「不写这个设置也一切正常」:东西都在同一个模块里,internal 就够用;等项目拆成好几个模块,权限问题才会浮出水面,而那时你已经会这一招了。

使用建议照搬本课的常量哲学:默认从紧,需要再放宽。状态类的字段先按「读 public、写 private」声明,真的出现合法的外部修改需求,再考虑放宽写权限或提供专门的修改函数。

使用建议照搬正课的常量哲学:默认从紧,需要再放宽。存状态的变量先按「读 public、写 private」声明,真出现合法的外部修改需求,再考虑放宽写权限、或专门开一个修改函数给别人调。

四、小测验

var<private> Score<public>:int = 0 这行声明的意思是?

来源

本文整理自 Epic 官方文档与社区教程:Specifiers and Attributes in Verse(官方文档)↗ · UEFN Verse: Access Specifiers(Romero Blueprints,含逐个组合示例)↗