在Swift 3中,我编写了一个自定义运算符prefix operator §,该方法在将String作为值并返回LocalizedString结构(保持键和值)的方法中使用。

public prefix func §(key: String) -> LocalizedString {
    return LocalizedString(key: key)
}

public struct LocalizedString {
    public var key: String
    public var value: String

    public init(key: String) {
        let translated = translate(using: key) // assume we have this
        self.key = key
        self.value = translated ?? "!!\(key)!!"
    }
}

(是的,我知道很棒的L10n enum in SwiftGen,但是我们正在从后端下载字符串,而这个问题更多的是关于如何使用自定义运算符的)

但是如果我们想从§运算符的结果中获取转换后的值(即,从结果value的属性LocalizedString),该怎么办?
let translation = §"MyKey".value // Compile error "Value of type 'String' has no member 'value'"

我们当然可以通过将其包装在括号(§"MyKey").value中来轻松修复该编译错误。但是,如果不想这样做。 是否可以为自定义运算符设置与“点”文字相关的优先级?

是的,我知道只有中缀运算符可以声明优先级,但是以某种方式使用优先级才能实现我想要的是有意义的:
precedencegroup Localization { higherThan: DotPrecedence } // There is no such group as "Dot"
prefix operator §: Localization

要标记Swift编译器首先应评估§"MyKey"并理解它不是字符串,而是实际上的LocalizedString(结构)。

觉得这不太可能吗?我想念什么?

最佳答案

.与标准库中定义的所有其他运算符不同,它由编译器提供。它的语法是Explicit Member Expressions

具有比.更高的优先级并不是编译器应允许您执行的操作,因为这是一个基本的用例。想象一下,如果编译器启用了这样的功能,您可以做什么:

-"Test".characters.count

如果您的优先级可能高于.,则编译器必须检查所有可能性:
(-"Test").characters.count   // func -(s: String) -> String
(-("Test".characters)).count // func -(s: String.CharacterView) -> String.CharacterView
-("Test".characters.count)   // func -(s: Int) -> Int

这将
  • 可能会增加很多编译时间
  • 含糊不清
  • 添加重载后可能更改现有代码的行为

  • 我建议您做的是放弃一个新的运算符,只不过是通过将一些特定的行为压缩为一个晦涩的角色来增加更多的认知负担。这是我的方法:
    extension String {
        var translatedString : String {
            return translate(using: self)
        }
    }
    
    "MyKey".localizedString
    

    或者,如果您想使用LocalizedString:
    extension String {
        var localized : LocalizedString {
            return LocalizedString(key: self)
        }
    }
    
    "MyKey".localized.value
    

    这些版本更加全面。

    08-17 05:34