简体   繁体   English

#file 是否被视为 Swift 中的文字字符串?

[英]Is #file considered a literal String in Swift?

Bug > Swift > Enum > String Protocol错误> Swift >枚举>字符串协议


I was attempting to create an enumeration in which all its elements were file names, and I stumbled across something interesting.我试图创建一个枚举,其中所有元素都是文件名,我偶然发现了一些有趣的东西。 Like so:像这样:

enum FileNames: String {
     case main = #file
}

This resulted in an internal error.这导致了内部错误。 (Segmentation Fault: 11) (分段错误:11)


I was able to figure how to get an actual error message:我能够弄清楚如何获得实际的错误消息:

enum Foo: String {
    case one = "\(1)"
}

Error: Raw value for enum case must be a literal


Related Questions:相关问题:
• Is #file considered a String literal? #file是否被视为字符串文字?
• Why does #file break the enum? • 为什么#file破坏枚举? Should this be reported on bugs.swift.org?这是否应该在 bugs.swift.org 上报告?
• I noticed that replacing String to Int and #file to #line causes the same issue. • 我注意到将String替换为Int并将#file#line会导致同样的问题。 Is this a hint?这是提示吗?


Color Literals Don't Work颜色文字不起作用

I thought they did, but I made a mistake.我以为他们做到了,但我犯了一个错误。 It also causes the same internal error.它也会导致相同的内部错误。

import UIKit

enum ColorEnum: UIColor {
    case foo = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0)
}

The Swift Programming Language (Swift 5.2) Swift 编程语言 (Swift 5.2)

According to Apple, #file is considered a literal:根据 Apple 的说法, #file被认为是文字:

#file 根据 Apple 描述为文字


What about nil Literals?那么 nil 字面量呢?

These also crash the compiler.这些也会使编译器崩溃。

enum Foo: String? {
    case breaks = nil
}

23 Characters of Mass Destruction enum I:Int?{case a=nil} Mass Destruction enum I:Int?{case a=nil} 23 个字符


Bug Fixed错误修复

The crash has now been fixed, it has been merged officially into Swift here: Merged on GitHub Here's the bug report: SR-12998 .崩溃现已修复,它已正式合并到 Swift 中: Merged on GitHub这是错误报告: SR-12998 It has officially been implemented in Swift 5.4已在 Swift 5.4 中正式实现

Adding Support!添加支持!
The use of magic literals as raw values for enum cases is being supported here: SR-13022这里支持使用魔法文字作为枚举案例的原始值: SR-13022

Yes, #file and #line are literal expressions but your program is still ill-formed.是的, #file#line文字表达式,但您的程序仍然是格式错误的。

The Swift language reference says : Swift 语言参考

A literal expression consists of either an ordinary literal (such as a string or a number), an array or dictionary literal, a playground literal, or one of the following special literals:文字表达式由普通文字(例如字符串或数字)、数组或字典文字、游乐场文字或以下特殊文字之一组成:

#file — String — The name of the file in which it appears. #file — 字符串 — 出现的文件的名称。

#line — Int — The line number on which it appears. #line — Int — 它出现的行号。

[...] [...]

Let's also note the grammar:我们还要注意语法:

literal-expression → literal
literal-expression → array-literal | dictionary-literal | playground-literal
literal-expression → #file | #line | #column | #function | #dsohandle

Now let us consider the grammar of the enum you are defining.现在让我们考虑您正在定义的枚举的语法 I am only including the most relevant parts here you can verify the complete deduction yourself:我在这里只包括最相关的部分,您可以自己验证完整的推论:

enum-declaration → attributes opt access-level-modifier opt raw-value-style-enum
[...]
raw-value-style-enum → enum enum-name generic-parameter-clause opt type-inheritance-clause generic-where-clause opt { raw-value-style-enum-members }
[...]
raw-value-assignment → = raw-value-literal
raw-value-literal → numeric-literal | static-string-literal | boolean-literal

It's noteworthy that only numeric-literal , static-string-literal , boolean-literal are allowed.值得注意的是,只允许numeric-literalstatic-string-literalboolean-literal If we look at their definitions, it's clear that those # literals thus do not match the raw-value-literal rule:如果我们查看它们的定义,很明显这些#字面量因此与raw-value-literal规则不匹配:

numeric-literal → -opt integer-literal | -opt floating-point-literal
boolean-literal → true | false
static-string-literal → string-literal-opening-delimiter quoted-text opt string-literal-closing-delimiter
static-string-literal → multiline-string-literal-opening-delimiter multiline-quoted-text opt multiline-string-literal-closing-delimiter

All relevant rules for completely defining static-string-literal are long, but it's still trivial to see that static-string-literal cannot be deduced to #file and cannot include interpolation.完全定义static-string-literal的所有相关规则都很长,但是看到static-string-literal不能推导出为#file并且不能包含插值仍然是微不足道的。 (That's what makes it static.) (这就是使它成为 static 的原因。)

So the Swift compiler is indeed right in refusing your program.所以 Swift 编译器拒绝你的程序确实是正确的。 Still, a modern compiler shouldn't simply crash on an illegal program, so it might be worth reporting this issue.尽管如此,现代编译器不应该简单地在非法程序上崩溃,因此可能值得报告这个问题。

This is definitely a bug, so worth submitting feedback to Apple (although they documented that those #file, #function, etc. are special literals )这绝对是一个错误,因此值得向 Apple 提交反馈(尽管他们记录了那些 #file、#function 等是特殊文字

Anyway, probably the following workaround can be helpful in some use-cases:无论如何,在某些用例中,以下解决方法可能会有所帮助:

enum FileNames {
    static let main = FileNames.file(#file)
    case file(String)
}

Swift 5.4 fixes the crash Swift 5.4 修复了崩溃

Swift 5.4 implements the bugfix from SR-12998 Swift 5.4 实现了来自SR-12998的错误修复

Instead of the compiler crashing, it now displays descriptive error messages:它现在显示描述性错误消息,而不是编译器崩溃:


Magic Literals from Strings来自字符串的魔法文字

enum Foo: String {
    // Compiler Error: Use of '#file' literal as raw value for enum case is not supported
    case b = #file
    // Compiler Error: Use of '#function' literal as raw value for enum case is not supported
    case c = #function
}

Magic Literals from Ints来自 Ints 的魔法文字

enum B: Int {
    // Compiler Error: Use of '#line' literal as raw value for enum case is not supported
    case b = #line
    // Compiler Error: Use of '#column' literal as raw value for enum case is not supported
    case c = #column
}

Magic Literals from UnsafeRawPointers UnsafeRawPointers 中的魔法文字

extension UnsafeRawPointer: ExpressibleByIntegerLiteral {}
enum Wo: UnsafeRawPointer {
    // Compiler Error: Use of '#dsohandle' literal as raw value for enum case is not supported
    case wo = #dsohandle
}

Using the Magic Literal nil in this way now displays a different error instead of crashing the compiler.以这种方式使用 Magic Literal nil现在会显示不同的错误,而不是使编译器崩溃。

enum Foo: String? {
    case breaks = nil
}
enum I:Int?{case a=nil}

It's not completely fixed:它没有完全修复:

However, the magic literal nil still can cause the compiler to crash:然而,神奇的文字nil仍然会导致编译器崩溃:

extension Optional: ExpressibleByIntegerLiteral where Wrapped == Int {}
enum Foo: Int? {
    // Compiler Crashes: Segmentation fault: 11
    case c = nil
}

Also the magic literal for UIColor still cause the compiler to crash: UIColor 的魔法文字仍然会导致编译器崩溃:

import UIKit
extension UIColor: ExpressibleByIntegerLiteral {}
enum ColorEnum: UIColor {
    // Compiler Crashes: Segmentation fault: 11
    case foo = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM