A TStringBuilder is basically a stack-allocated string, whereas FString is always heap-allocated.
Hence using TStringBuilder is much faster and does not result in any system-calls.
Use it for parts of the code, where speed matters.
Even when you are building an FString, it's better to first create a TStringBuilder and then convert it to an FString once before printing for example (FString + FString may still result in a system-call).
The "<T>" is the size, basically how many characters it can contain and store on the stack (internal fixed size array).
If you add too many characters than specified (using <T>), it will automatically become a heap-allocated dynamic array.
TStringBuilder<512> Message; // Reserve memory on the stack
Message
<< TEXT("This message is exactly ")
<< 512
<< TEXT(" characters long.");
Message
<< TEXT("\n")
<< TEXT("And a formatted float looks like ");
Message.Appendf(TEXT("%.2f"), 4.2f);
UE_LOGFMT(LogTemp, Warning, "{Message}", Message); // Can accept TStringBuilder directly
GEngine->AddOnScreenDebugMessage(-1, 25.f, FColor::Yellow, Message.ToString()); // Requires an FString
Think of this as if you were to use the regular C++ std::cout.
Use << for simple, non formatted texts (but always make sure to use TEXT()).
Use .Appendf(TEXT()) for formatted texts (not required for simple variables or things like "\n".
To convert to an FString, simply use .ToString().
FORCEINLINE void ReturnMessage (TStringBuilder<32> &Message)
{
const float MyFloat {42.4242};
Message << TEXT("The value is ");
Message.Appendf(TEXT("%.4f"), MyFloat);
}
Since TStringBuilder is stack-allocated, you cannot use it as a direct return-type. Once it goes out of scope, it's gone. Hence the only solution here is to define it outside and then use the reference to edit/set it. Calling it correctly would look like the following:
TStringBuilder<32> Message;
ReturnMessage(Message);
UE_LOGFMT(LogTemp, Warning, "{}", Message);