objective-c 字符串常量和字符串文字有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25746/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 20:43:40  来源:igfitidea点击:

What's the difference between a string constant and a string literal?

objective-cstring

提问by Benedict Cohen

I'm learning objective-C and Cocoa and have come across this statement:

我正在学习 Objective-C 和 Cocoa,并且遇到了以下语句:

The Cocoa frameworks expect that global string constants rather than string literals are used for dictionary keys, notification and exception names, and some method parameters that take strings.

Cocoa 框架期望全局字符串常量而不是字符串文字用于字典键、通知和异常名称以及一些采用字符串的方法参数。

I've only worked in higher level languages so have never had to consider the details of strings that much. What's the difference between a string constant and string literal?

我只在高级语言中工作过,所以从来没有必要考虑那么多字符串的细节。字符串常量和字符串文字有什么区别?

回答by Chris Hanson

In Objective-C, the syntax @"foo"is an immutable, literalinstance of NSString. It does not make a constant string from a string literal as Mike assume.

在Objective-C,语法@"foo"不可变的文字的实例NSString。它不会像 Mike 假设的那样从字符串文字中生成常量字符串。

Objective-C compilers typically dointern literal strings within compilation units — that is, they coalesce multiple uses of the same literal string — and it's possible for the linker to do additional interning across the compilation units that are directly linked into a single binary. (Since Cocoa distinguishes between mutable and immutable strings, and literal strings are always also immutable, this can be straightforward and safe.)

Objective-C 编译器通常在编译单元内执行内部文本字符串——也就是说,它们合并同一个文本字符串的多次使用——并且链接器可以在直接链接到单个二进制文件的编译单元之间进行额外的实习。(因为 Cocoa 区分可变和不可变字符串,并且文字字符串总是不可变的,这可以是直接和安全的。)

Constantstrings on the other hand are typically declared and defined using syntax like this:

另一方面,常量字符串通常使用如下语法声明和定义:

// MyExample.h - declaration, other code references this
extern NSString * const MyExampleNotification;

// MyExample.m - definition, compiled for other code to reference
NSString * const MyExampleNotification = @"MyExampleNotification";

The point of the syntactic exercise here is that you can make uses ofthe string efficient by ensuring that there's only one instance of that string in use even across multiple frameworks(shared libraries) in the same address space. (The placement of the constkeyword matters; it guarantees that the pointer itself is guaranteed to be constant.)

此处语法练习的重点是,您可以通过确保即使在同一地址空间中的多个框架(共享库)中也只有该字符串的一个实例在使用,从而有效地使用该字符串。(关键字的位置很重要;它保证指针本身是常量。)const

While burning memory isn't as big a deal as it may have been in the days of 25MHz 68030 workstations with 8MB of RAM, comparing strings for equality can take time. Ensuring that most of the time strings that are equal will also be pointer-equal helps.

虽然在 25MHz 68030 工作站和 8MB RAM 的时代,刻录内存并不是一件大事,但比较字符串的相等性可能需要时间。确保大多数时间相等的字符串也将是指针相等的帮助。

Say, for example, you want to subscribe to notifications from an object by name. If you use non-constant strings for the names, the NSNotificationCenterposting the notification could wind up doing a lot of byte-by-byte string comparisons when determining who is interested in it. If most of these comparisons are short-circuited because the strings being compared have the same pointer, that can be a big win.

例如,假设您想按名称订阅来自对象的通知。如果您对名称使用非常量字符串,则NSNotificationCenter在确定谁对它感兴趣时,发布通知可能会进行大量逐字节的字符串比较。如果这些比较中的大多数都因为被比较的字符串具有相同的指针而短路,那可能是一个巨大的胜利。

回答by Jano

Some definitions

一些定义

A literalis a value, which is immutable by definition. eg: 10
A constantis a read-only variable or pointer. eg: const int age = 10;
A string literalis a expression like @"". The compiler will replace this with an instance of NSString.
A string constantis a read-only pointer to NSString. eg: NSString *const name = @"John";

文字是一个数值,它是由定义不可变的。例如:10
常数是只读变量或指针。例如:const int age = 10;
字符串文字就像是一个表达式@""。编译器将用NSString.
一个字符串常量是只读指针NSString。例如:NSString *const name = @"John";

Some comments on the last line:

最后一行的一些评论:

  • That's a constant pointer, not a constant object1. objc_sendMsg2doesn't care if you qualify the object with const. If you want an immutable object, you have to code that immutability inside the object3.
  • All @""expressions are indeed immutable. They are replaced4at compile time with instances of NSConstantString, which is a specialized subclass of NSStringwith a fixed memory layout5. This also explains why NSStringis the only object that can be initialized at compile time6.
  • 那是一个常量指针,而不是一个常量对象1objc_sendMsg2不在乎您是否使用const. 如果你想要一个不可变的对象,你必须在对象3内编码该不变性。
  • 所有@""表达式确实是不可变的。它们在编译时被4替换为 的实例NSConstantString,它是NSString具有固定内存布局5的特殊子类。这也解释了为什么NSString是唯一可以在编译时初始化的对象6

A constant stringwould be const NSString* name = @"John";which is equivalent to NSString const* name= @"John";. Here, both syntax and programmer intention are wrong: const <object>is ignored, and the NSStringinstance (NSConstantString) was already immutable.

常量字符串将是const NSString* name = @"John";这相当于NSString const* name= @"John";。在这里,语法和程序员的意图都是错误的:const <object>被忽略,并且NSString实例 ( NSConstantString) 已经是不可变的。

1The keyword constapplies applies to whatever is immediately to its left. If there is nothing to its left, it applies to whatever is immediately to its right.

1该关键字const适用于紧邻其左侧的任何内容。如果它的左边没有任何东西,它适用于它右边的任何东西。

2This is the function that the runtime uses to send all messages in Objective-C, and therefore what you can use to change the state of an object.

2这是运行时用来在Objective-C 中发送所有消息的函数,因此您可以使用它来更改对象的状态。

3Example: in const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects];const doesn't prevent the last statement.

3示例:in const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects];const 不会阻止最后一条语句。

4The LLVM code that rewrites the expression is RewriteModernObjC::RewriteObjCStringLiteralin RewriteModernObjC.cpp.

4重写表达式的 LLVM 代码RewriteModernObjC::RewriteObjCStringLiteral位于 RewriteModernObjC.cpp 中。

5To see the NSConstantStringdefinition, cmd+click it in Xcode.

5要查看NSConstantString定义,请在 Xcode 中 cmd+单击它。

6Creating compile time constants for other classes would be easy but it would require the compiler to use a specialized subclass. This would break compatibility with older Objective-C versions.

6为其他类创建编译时常量很容易,但需要编译器使用专门的子类。这会破坏与旧的 Objective-C 版本的兼容性。



Back to your quote

回到您的报价

The Cocoa frameworks expect that global string constants rather than string literals are used for dictionary keys, notification and exception names, and some method parameters that take strings. You should always prefer string constants over string literals when you have a choice. By using string constants, you enlist the help of the compiler to check your spelling and thus avoid runtime errors.

Cocoa 框架期望全局字符串常量而不是字符串文字用于字典键、通知和异常名称以及一些采用字符串的方法参数。当您有选择时,您应该始终更喜欢字符串常量而不是字符串文字。通过使用字符串常量,您可以获得编译器的帮助来检查您的拼写,从而避免运行时错误。

It says that literals are error prone. But it doesn't say that they are also slower. Compare:

它说文字容易出错。但这并不是说它们也更慢。相比:

// string literal
[dic objectForKey:@"a"];

// string constant
NSString *const a = @"a";
[dic objectForKey:a];

In the second case I'm using keys with const pointers, so instead [a isEqualToString:b], I can do (a==b). The implementation of isEqualToString:compares the hash and then runs the C function strcmp, so it is slower than comparing the pointers directly. Which is why constant strings are better:they are faster to compare and less prone to errors.

在第二种情况下,我使用带有 const 指针的键,所以相反[a isEqualToString:b],我可以做(a==b). 的实现是先isEqualToString:比较hash然后运行C函数strcmp,所以比直接比较指针慢。这就是为什么常量字符串更好的原因:它们比较起来更快,而且更不容易出错。

If you also want your constant string to be global, do it like this:

如果您还希望常量字符串是全局的,请这样做:

// header
extern NSString *const name;
// implementation
NSString *const name = @"john";

回答by Brad Wilson

Let's use C++, since my Objective C is totally non-existent.

让我们使用 C++,因为我的 Objective C 完全不存在。

If you stash a string into a constant variable:

如果将字符串存储到常量变量中:

const std::string mystring = "my string";

Now when you call methods, you use my_string, you're using a string constant:

现在,当您调用方法时,您使用的是 my_string,您使用的是字符串常量:

someMethod(mystring);

Or, you can call those methods with the string literal directly:

或者,您可以直接使用字符串文字调用这些方法:

someMethod("my string");

The reason, presumably, that they encourage you to use string constants is because Objective C doesn't do "interning"; that is, when you use the same string literal in several places, it's actually a different pointer pointing to a separate copy of the string.

他们鼓励你使用字符串常量的原因大概是因为 Objective C 不做“实习”;也就是说,当您在多个地方使用相同的字符串文字时,它实际上是指向该字符串的单独副本的不同指针。

For dictionary keys, this makes a huge difference, because if I can see the two pointers are pointing to the same thing, that's much cheaper than having to do a whole string comparison to make sure the strings have equal value.

对于字典键,这有很大的不同,因为如果我能看到两个指针指向同一个东西,这比必须进行整个字符串比较以确保字符串具有相等的值要便宜得多。

Edit:Mike, in C# strings are immutable, and literal strings with identical values all end pointing at the same string value. I imagine that's true for other languages as well that have immutable strings. In Ruby, which has mutable strings, they offer a new data-type: symbols ("foo" vs. :foo, where the former is a mutable string, and the latter is an immutable identifier often used for Hash keys).

编辑:Mike,在 C# 中,字符串是不可变的,并且具有相同值的文字字符串都指向相同的字符串值。我想对于其他具有不可变字符串的语言也是如此。在具有可变字符串的 Ruby 中,它们提供了一种新的数据类型:符号(“foo”与 :foo,其中前者是可变字符串,后者是常用于哈希键的不可变标识符)。