《Unreal 对 C++ 做了什么》系列 (09/54)
09. 字符串的“三重奏”:FName, FText, FString 的分工与转换 字符串的“三重奏” 🎭
🚀 导言:为什么 std::string 不够用?
游戏开发对字符串的要求非常极端:
- 极速查找:每一帧都要在成千上万个资源名中查找对应的那个,不能接受逐字符对比。
- 本地化:同一句台词,在中文下是“你好”,英文下是“Hello”,程序逻辑不能变。
- 动态拼接:玩家的名字、伤害数值,需要频繁修改。
标准 C++ 的std::string无法同时高效满足这三个需求。因此,UE 设计了三个专门的类来各司其职。
🔑 1. FName:性能的极致(静态标识符)
FName是 UE 为了资源索引而设计的黑科技。
本质:它不是字符串,而是一个整数 ID。
机制:当你创建一个
FName时,UE 会把这个字符串存入一个全局的“名字表”(Name Table),并给你返回一个索引。优势:
极速对比:比较两个
FName是否相等,只需要对比两个整数,不需要逐位比对字符。内存去重:同样的字符串,在内存中只存一份。
适用场景:骨骼名、材质参数名、资源路径、标签 (Tag)。
注意:
FName不区分大小写,且不可被修改。
🔑 2. FText:本地化的核心(用户界面)
FText是唯一用于显示给玩家看的字符串。
本质:它是“字符串”+“本地化上下文”。
核心特性:
本地化 (Localization):它支持自动根据玩家的语言设置切换内容。
文本格式化:通过
FText::Format可以安全地插入参数。适用场景:物品描述、对话台词、菜单标题。
性能提示:
FText的对比操作非常慢,严禁用于逻辑判断(如if (Text == "Attack"))。
🔑 3. FString:唯一的动态修改器(变色龙)
FString是三者中最接近std::string的,它允许你像普通 C++ 那样对字符进行切割、拼接、搜索。
- 本质:一个动态分配内存的字符数组 (
TArray<TCHAR>)。 - 核心特性:支持大量操作函数(
Printf,Split,Join,Contains)。 - 适用场景:文件名处理、日志打印 (
UE_LOG)、需要解析的动态字符串。
🔄 转换矩阵:它们如何互通?
在开发中,你不可避免地要在三者之间转换。转换虽然方便,但有性能开销:
| 从 \ 到 | FName | FString | FText |
|---|---|---|---|
| FName | - | Name.ToString() | FText::FromName(Name) |
| FString | FName(*String) | - | FText::FromString(String) |
| FText | 无直接转换 (需先转 String) | Text.ToString() | - |
核心知识点:
*运算符
在 UE 中,你会经常看到*MyString。这并不是取解引用,而是FString重载了运算符,返回一个const TCHAR*。很多函数(如UE_LOG或FName构造函数)都需要这个底层的 C 指针。
🛠️ 性能陷阱与避坑指南
- 不要在 Tick 里创建 FName:
虽然FName查找很快,但将FString转换成FName(即查表入表的过程)是需要开销的。预先在BeginPlay或构造函数里定义好。 - FString 的拷贝:
传递FString参数时,请务必使用常量引用(const FString&),否则会产生不必要的内存分配。 - UI 文本必须用 FText:
如果你在 C++ 里用FString定义 UI 文本,后期做多语言翻译时,你将不得不重写所有相关代码。
📊 总结速查
- 查表/索引/资源名➔ 使用
FName(快,省,不可改)。 - 玩家看得到的文字➔ 使用
FText(本地化,安全)。 - 需要逻辑处理/拼接➔ 使用
FString(灵活,较重)。
结语
UE 的字符串系统是 C++ “性能 vs 功能”平衡的典范。通过将“标识符”、“文本内容”和“动态处理”拆分开,UE 确保了在大规模游戏开发中,既能跑得快(FName),又能卖得广(FText 本地化)。
下一篇我们将探讨:《10. 逻辑的生命线:Delegates (委托) 的深度解析》。我们将看看 UE 如何通过委托系统实现解耦,让你的 C++ 代码能优雅地通知蓝图或其他系统。