ios - Xcode 重构“转换为 Switch”
问题描述
Xcode Refactor 有一个名为“Convert to Switch”的功能。我正在寻找可以由函数使用并转换为 switch 流语句的代码示例。
解决方案
更新
正如您所指出的,Convert to Switch
!= Convert To Switch Statement
。为了理解为什么,我们需要知道 Xcode 重构特性是如何在底层工作的。
我发现了什么:
这是一篇关于该主题的精彩文章: https ://levelup.gitconnected.com/uncovering-xcode-indexing-8b3f3ff82551
它指向一个swift
开源仓库:https ://github.com/apple/swift
Xcode 重构是通过一个SourceKit
框架完成的,该框架位于一个 swift repo 中。
这是与 Xcode 通信的 SourceKit 协议:https ://github.com/apple/swift/blob/main/tools/SourceKit/docs/Protocol.md
在内部,当我们选择“重构”时,Xcode以某种方式(通过 XPC)向SourceKit 发送消息之类的东西。source.request.workspace.refactoring
并且在某处有一个“索引文件”,因此SourceKit
可以立即(而不是在 5 分钟内 :))向您建议对于当前代码片段来说足够/可能的选项。
我已经swift
从 github 加载了 repo(大约 30MB),导航到SourceKit
代码并试图找到与source.request.workspace.refactoring
.
代码中的某处是对swift/IDE/RefactoringKinds.def
. 我将复制粘贴此文件的内容:
#ifndef REFACTORING
#define REFACTORING(KIND, NAME, ID)
#endif
#ifndef SEMANTIC_REFACTORING
#define SEMANTIC_REFACTORING(KIND, NAME, ID) REFACTORING(KIND, NAME, ID)
#endif
#ifndef RANGE_REFACTORING
#define RANGE_REFACTORING(KIND, NAME, ID) SEMANTIC_REFACTORING(KIND, NAME, ID)
#endif
#ifndef INTERNAL_RANGE_REFACTORING
#define INTERNAL_RANGE_REFACTORING(KIND, NAME, ID) RANGE_REFACTORING(KIND, NAME, ID)
#endif
#ifndef CURSOR_REFACTORING
#define CURSOR_REFACTORING(KIND, NAME, ID) SEMANTIC_REFACTORING(KIND, NAME, ID)
#endif
/// Rename and categorise the symbol occurrences at provided locations
/// (syntactically).
REFACTORING(GlobalRename, "Global Rename", rename.global)
/// Categorize source ranges for symbol occurrences at provided locations
/// (syntactically).
REFACTORING(FindGlobalRenameRanges, "Find Global Rename Ranges", rename.global.find-ranges)
/// Find and categorize all occurences of the file-local symbol at a given
/// location.
REFACTORING(FindLocalRenameRanges, "Find Local Rename Ranges", rename.local.find-ranges)
/// Find and rename all occurences of the file-local symbol at a given
/// location.
CURSOR_REFACTORING(LocalRename, "Local Rename", rename.local)
CURSOR_REFACTORING(FillProtocolStub, "Add Missing Protocol Requirements", fillstub)
CURSOR_REFACTORING(ExpandDefault, "Expand Default", expand.default)
CURSOR_REFACTORING(ExpandSwitchCases, "Expand Switch Cases", expand.switch.cases)
CURSOR_REFACTORING(LocalizeString, "Localize String", localize.string)
CURSOR_REFACTORING(SimplifyNumberLiteral, "Simplify Long Number Literal", simplify.long.number.literal)
CURSOR_REFACTORING(CollapseNestedIfStmt, "Collapse Nested If Statements", collapse.nested.ifstmt)
CURSOR_REFACTORING(ConvertToDoCatch, "Convert To Do/Catch", convert.do.catch)
CURSOR_REFACTORING(TrailingClosure, "Convert To Trailing Closure", trailingclosure)
CURSOR_REFACTORING(MemberwiseInitLocalRefactoring, "Generate Memberwise Initializer", memberwise.init.local.refactoring)
CURSOR_REFACTORING(AddEquatableConformance, "Add Equatable Conformance", add.equatable.conformance)
CURSOR_REFACTORING(ConvertCallToAsyncAlternative, "Convert Call to Async Alternative", convert.call-to-async)
CURSOR_REFACTORING(ConvertToAsync, "Convert Function to Async", convert.func-to-async)
CURSOR_REFACTORING(AddAsyncAlternative, "Add Async Alternative", add.async-alternative)
RANGE_REFACTORING(ExtractExpr, "Extract Expression", extract.expr)
RANGE_REFACTORING(ExtractFunction, "Extract Method", extract.function)
RANGE_REFACTORING(ExtractRepeatedExpr, "Extract Repeated Expression", extract.expr.repeated)
RANGE_REFACTORING(MoveMembersToExtension, "Move To Extension", move.members.to.extension)
RANGE_REFACTORING(ConvertStringsConcatenationToInterpolation, "Convert to String Interpolation", convert.string-concatenation.interpolation)
RANGE_REFACTORING(ExpandTernaryExpr, "Expand Ternary Expression", expand.ternary.expr)
RANGE_REFACTORING(ConvertToTernaryExpr, "Convert To Ternary Expression", convert.ternary.expr)
RANGE_REFACTORING(ConvertIfLetExprToGuardExpr, "Convert To Guard Expression", convert.iflet.to.guard.expr)
RANGE_REFACTORING(ConvertGuardExprToIfLetExpr, "Convert To IfLet Expression", convert.to.iflet.expr)
RANGE_REFACTORING(ConvertToComputedProperty, "Convert To Computed Property", convert.to.computed.property)
RANGE_REFACTORING(ConvertToSwitchStmt, "Convert To Switch Statement", convert.switch.stmt)
// These internal refactorings are designed to be helpful for working on
// the compiler/standard library, etc., but are likely to be just confusing and
// noise for general development.
INTERNAL_RANGE_REFACTORING(ReplaceBodiesWithFatalError, "Replace Function Bodies With 'fatalError()'", replace.bodies.with.fatalError)
#undef CURSOR_REFACTORING
#undef INTERNAL_RANGE_REFACTORING
#undef RANGE_REFACTORING
#undef SEMANTIC_REFACTORING
#undef REFACTORING
如您所见,Convert To Switch Statement
这里有 和Expand Switch Cases
,但没有Convert To Switch
。
所以我的猜测是,Xcode 在 UI 中向我们展示的要么是一个错误(他们忘记删除过时的东西),要么是某些实现的一部分,它不在当前版本的 Swift 存储库中。
无论如何,你可能会更深入地挖掘——我只是试图在短时间内调查它。:) 如果你真的需要这样做,那么除了探索SourceKit
协议之外,我想你可以在 Github 上打开一个问题——也许知道的人会解释一个真正的原因。
初步答案
让我们考虑这样一个例子:
enum SomeEnum {
case option1, option2, option3
}
func convertToSwitchExampleFunc(_ option: SomeEnum) {
if option == .option1 {
print("1")
}
if option == .option2 {
print("2")
}
if option == .option3 {
print("3")
}
}
func callingFunc() {
convertToSwitchExampleFunc(.option2)
}
如果您选择 的正文中的所有代码convertToSwitchExampleFunc
,然后选择Refactor
,Xcode 将不会显示“转换为开关”。
但是,如果您更改代码使其更类似于丑陋的“开关”实现(if-else-if-else
链):
func convertToSwitchExampleFunc(_ option: SomeEnum) {
if option == .option1 {
print("1")
}
else if option == .option2 {
print("2")
}
else if option == .option3 {
print("3")
}
}
然后 Xcode 将显示“转换为切换菜单”,自动重构的代码将如下所示:
func convertToSwitchExampleFunc(_ option: SomeEnum) {
switch option {
case .option1:
print("1")
case .option2:
print("2")
case .option3:
print("3")
default:
break
}
}
推荐阅读
- reactjs - 在 React 中从 Child 更新 Parent 状态而不触发 Child 的重新渲染
- html-webpack-plugin - 使用 pug、json、htmlwebpackplugin 访问嵌套对象
- kotlin - 在 kotlin android 开发中,布局(以编程方式)如何与没有 xml 的数据绑定一起工作?
- python - 错误:jupyter notebook 中不支持的类文件主要版本 56
- python - 使用数组中的名称创建 python 函数
- javascript - For 循环遍历 Array 不起作用。如何解决?
- java - Java 正则表达式在回顾中只能使用 1 个量词(需要 2 个)
- c# - 使用位图提高 xamarin.forms 中的对比度导致类型加载异常
- c# - Blazor 中的“无法从绑定属性‘绑定值’推断属性名称”错误
- php - ZF2 基于路由约束路由多个控制器