Things to know about FName
FName includes an optional instance number
Most FName
in UE don’t contain numbers, but an optional number IS
supported as a part of the FName
.
To help visualize this, here’s a table with some examples:
Expression | PlainName | Number | ToString() |
---|---|---|---|
FName("Foo") |
"Foo" |
0 |
"Foo" |
FName("Foo", 0) |
"Foo" |
0 |
"Foo" |
FName("Foo_0") |
"Foo" |
1 |
"Foo_0" |
FName("Foo", 1) |
"Foo" |
1 |
"Foo_0" |
FName("Foo_1") |
"Foo" |
2 |
"Foo_1" |
FName("Foo", 2) |
"Foo" |
2 |
"Foo_1" |
Significantly, notice that the internal Number is always 1
greater
than the number represented in the string.
This allows for FName("Foo")
to be functionally equivalent
to FName("Foo", 0)
and distinctly different
from FName("Foo_0")
.
The operator==
considers both the PlainString
part of the
FName
and the Number
part of the name, such that
FName("Foo", 1) != FName("Foo", 2)
If you want to compare only the PlainString
part of the name,
such that FName("Foo", 1)
will be considered equivalent to FName("Foo", 2)
,
the most efficient way to do so is to use GetComparisonIndex()
, like:
if (FName("Foo_1").ComparisonIndex() == FName("Foo_2").ComparisonIndex())
{
// This is true.
// "Foo" == "Foo"; the "_1" and "_2" are ignored by ComparisonIndex()
}
Sample code
Run this code to help understand how FName
handles the optional Number data:
FName Foo ("Foo"); // same as FName("Foo", 0)
FName Foo1 ("Foo", 1); // same as FName("Foo_0")
FName Foo2 ("Foo_1"); // same as FName("Foo", 2)
UE_LOG(LogTemp, Log, TEXT("Foo PlainString=\"%s\", Number=%d, ToString=\"%s\""), *Foo.GetPlainNameString(), Foo.GetNumber(), *Foo.ToString());
UE_LOG(LogTemp, Log, TEXT("Foo1 PlainString=\"%s\", Number=%d, ToString=\"%s\""), *Foo1.GetPlainNameString(), Foo1.GetNumber(), *Foo1.ToString());
UE_LOG(LogTemp, Log, TEXT("Foo2 PlainString=\"%s\", Number=%d, ToString=\"%s\""), *Foo2.GetPlainNameString(), Foo2.GetNumber(), *Foo2.ToString());
// All these comparison methods include both the PlainString AND the Number
UE_LOG(LogTemp, Log, TEXT("Foo == Foo1 ? %s"), Foo == Foo1 ? TEXT("true") : TEXT("false"));
// Optimal way to compare JUST the PlainString part, ignoring the Number part
UE_LOG(LogTemp, Log, TEXT("Foo.GetComparisonIndex() == Foo1.GetComparisonIndex() ? %s"), Foo.GetComparisonIndex() == Foo1.GetComparisonIndex() ? TEXT("true") : TEXT("false"));
Result
LogTemp: Foo PlainString="Foo", Number=0, ToString="Foo"
LogTemp: Foo1 PlainString="Foo", Number=1, ToString="Foo_0"
LogTemp: Foo2 PlainString="Foo", Number=2, ToString="Foo_1"
LogTemp: Foo == Foo1 ? false
LogTemp: Foo.GetComparisonIndex() == Foo1.GetComparisonIndex() ? true
Thanks!
Thanks to Dirtsleeper
on the Unreal Source
Discord for bringing this
non-obvious behavior to my attention.