Swift中代码的出现

上个月,我参加了Advent of Code,这是一个每天编写小型程序难题的日历。

这些难题通常可以用一百行左右的代码来解决,而在诸如Python这样的高生产率语言中,它们最容易解决。 我解决了Swift中的难题,从而获得了有趣的体验。 (好的,坦白的说,随着圣诞节的临近,难题变得更加耗时了,正好在我没有时间的时候,所以我还没有全部完成。)

总体而言,在Swift中进行代码问世(AoC)很有趣,但是一路上遇到了一些障碍,使事情变得比应有的尴尬。

当我浏览拼图时,我记下了我遇到的每个“剪纸”,并在下面以不特定的顺序展示它们。 其中大多数与标准库有关-语言本身的生产力非常高。

出口()

在简短的脚本程序中要做的一个非常普遍的事情是结束程序。 在AoC中,这经常在我的程序找到解决方案并且想要完成时发生。 Swift中有哪些选项?

您可以调用fatalError()但这是不对的-它会打印出令人恐惧的堆栈跟踪。

正确的解决方案是exit()但是很奇怪,这不是标准库的一部分,您必须import Darwin才能使用它。 这意味着您的程序无法在Linux上编译,因此您实际上必须这样做:

  #if os(Linux) 
导入Glibc
#其他
进口达尔文
#万一
  //现在我可以调用exit() 
退出(0)

啊。 Swift应该将exit() (或类似的东西)添加到标准库中。

对数组求和

想要将一个数组的所有元素相加是非常普遍的。 在Swift中,您可以这样操作:

 设total = array.reduce(0,+) 

我认为诸如reduce()类的功能概念对于像求和数组之类的简单操作来说是不必要的复杂性。 将array.sum()添加到标准库是合理的。 实现将是这样的:

  //这应该在标准库中 
扩展序列,其中元素:数字{
func sum()->元素{
返回reduce(0,+)
}
}
  //现在我可以这样做 
让总数= array.sum()

常用表达

目前,在Swift中,没有语言或标准库支持正则表达式。 要使用正则表达式,您必须import Foundation并处理NSRegularExpression ,这不是现代的Swifty API。

正则表达式在一些难题中很有用,Swift当然应该在语言中添加正则表达式文字。

上壳体和下壳体

Swift具有string.uppercased()string.lowercased()来返回字符串的大写或小写版本。 但是奇怪的是,没有办法将Character大写或小写。 我最终将字符转换为字符串,将其大写,然后将字符串转换回字符,这很浪费。 将character.uppercased()character.lowercased()到标准库中似乎很有用。

更新 :Apple的Michael Ilseman告诉我, character.uppercased()character.lowercased()已在Swift 5中实现! 它们确实返回String而不是Character ,因为是Unicode。

基本文件I / O

标准库不提供任何从磁盘读取的支持。 为此,您必须import Foundation并处理BundleFileManager和朋友。 如果要懒惰地读取文件(例如,要逐行使用文件而不将全部内容读入内存),则还必须处理FileHandle 。 所有这些都是非常令人不愉快的,您将最终想到Stack Overflow,为什么在地球上它必须如此复杂。

没有比Python更简单的了:

 with open('filename.txt') as file: 
for line in file:
print(line)

这个要点(Google在“逐行快速读取文件”方面的热门歌曲)显示了您在Swift中必须经历的那种痛苦。

创建2D数组

通常,Swift重视API命名中的冗长和描述性。 但是,有时这会使代码的可读性大大降低。 考虑一下:

C:

  //定义一个5x5的整数数组 
int array [5] [5];

迅速:

  //定义一个5x5的整数数组 
var array = [[Int]](重复:[Int](重复:0,计数:5),计数:5)

诚然,Swift已将元素初始化为零,而C尚未将其初始化为零,但是即使如此,也很难说Swift代码很漂亮。 嵌套的初始化程序很难看。

检查非空集合

在Swift中,您可以使用isEmpty属性检查集合是否为空。 但是,如果您要检查集合是否为非空并且有很长的代码行,则可能会很难理解。

 如果!users.filter {$ 0.isActive && $ 0.highScore> 50} .isEmpty 

!isEmpty相距很远,但是必须一起理解,这会损害可读性。 如果可以这样写会更好:

 如果users.filter {$ 0.isActive && $ 0.highScore> 50} .isNonEmpty 

现在,您可以更轻松地看到,我们正在查找是否有任何活跃用户的得分高于50。这很简单:

  //我认为这应该在标准库中 
扩展集合{
公共变量isNonEmpty:布尔{
返回!isEmpty
}
}

如果Swift有更多这样的小能力,那就太好了。

字符串,字符串,字符串

这是我在String的人体工程学中发现的一些问题。

  1. 如果要查找字符串是否包含特定字符,可以调用str.contains(_ element: Character) 。 但是,如果要查找字符串是否包含特定的子字符串,则必须import Foundation然后在NSString上调用str.contains(_ str: String)或在str.contains(_ other: T) where T : StringProtocol调用str.contains(_ other: T) where T : StringProtocol 。 奇怪的是,最后一个是Foundation的一部分,而不是标准库的一部分。 查找子字符串应该是标准库的一部分。
  2. String上没有用于修剪空格的方法。 您必须import Foundation并调用str.trimmingCharacters(in: .whitespacesAndNewlines) 。 可以给我们str.trimmed()吗? 哦,顺便说一句, .whitespacesAndNewlines是一个CharacterSet ,它是Foundation数据类型,与Set完全不同。
  3. 同样,也没有str.chomp()方法来删除字符串末尾的换行符。
  4. 假设您有一个类似"-1, 3, 4, 7"的字符串"-1, 3, 4, 7"并且想将其转换为["-1", "3", "4", "7"]类的数组。 解决方案是str.split(whereSeparator: { !"-0123456789".contains($0) }) 。 嗯 问题在于,没有采用SetStringsplit()版本—只有采用CharacterwhereSeparator谓词的版本。 如果有使用Set的版本,则可以编写let separators: Set = [",", " "]; str.split(on: separators) let separators: Set = [",", " "]; str.split(on: separators) 。 如果存在使用String的版本,则可以编写str.split(on: ", ")

数据结构

标准库提供的集合非常有限。 仅ArraySetDictionary可用。 几次我想要双端Deque但不包括在内。

我希望可以将更多的数据结构添加到标准库中,因为我可以想象像二进制搜索树和图形之类的东西也会有用。

反复循环浏览收藏集

如果您有Array ,则可以使用for element in array { }对其进行迭代。 但是,如果您想无限迭代该怎么办? 您可以执行此操作,但这很丑陋:

 环: 
而真实{
用于数组{
// 做点什么
如果someCondition {
断环
}
}
}

Python的“ itertools”模块具有cycle() ,它可以无限生成可迭代的元素。 如果Swift有类似的功能,那就太好了。

结论

我希望这篇文章不会让人感到烦恼-总体而言,我认为Swift的功能非常强大,并且具有巨大的潜力来增加其使用和适用性。 我希望在Swift 5之后解决这些问题时能取得进展。

我还建议将来参加代码问世-难题很有趣,并且不需要花费太长时间即可解决。