Scala 的代码风格怎么统一?这份 scalastyle 配置你可以无脑复制
Posted Shockang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala 的代码风格怎么统一?这份 scalastyle 配置你可以无脑复制相关的知识,希望对你有一定的参考价值。
前言
本文隶属于专栏《1000个问题搞定大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!
本专栏目录结构和参考文献请见1000个问题搞定大数据技术体系
正文
本文参考 Apache Spark 的 scalastyle 配置。
首先需要在 pom.xml 里面新增 scalastyle 的 plugin。
pom.xml
先定义 2 个和文件字符编码相关的全局变量。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
配置 scalastyle-maven-plugin
<plugin>
<groupId>org.scalastyle</groupId>
<artifactId>scalastyle-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<verbose>false</verbose>
<failOnViolation>true</failOnViolation>
<includeTestSourceDirectory>false</includeTestSourceDirectory>
<failOnWarning>false</failOnWarning>
<sourceDirectory>$basedir/src/main/scala</sourceDirectory>
<testSourceDirectory>$basedir/src/test/scala</testSourceDirectory>
<configLocation>scalastyle-config.xml</configLocation>
<outputFile>$basedir/target/scalastyle-output.xml</outputFile>
<inputEncoding>$project.build.sourceEncoding</inputEncoding>
<outputEncoding>$project.reporting.outputEncoding</outputEncoding>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
在项目根目录下定义 scalastyle 的配置文件:scalastyle-config.xml
scalastyle-config.xml
可以无脑复制的部分
<!--
这里参考的 Apache Spark 的 scala 代码风格配置文件。
如果希望关闭代码段的检查,可以在源代码中添加注释
在代码段之前和之后,使用以下语法:
// scalastyle:off
... // 用来破坏风格的东西
// scalastyle:on
也可以通过指定规则 ID 来单独取消一条规则,就像这样:
http://www.scalastyle.org/rules-0.7.0.html
// scalastyle:off no.finalize
override def finalize(): Unit = ...
// scalastyle:on no.finalize
这个文件分成了 3 个部分:
(1) 我们应当遵守的规则
(2) 我们想要遵守的规则,但是实际情况不允许。
(3) 我们不想遵守的规则
-->
<scalastyle>
<name>Scalastyle standard configuration</name>
<!-- ================================================================================ -->
<!-- 我们应当遵守的规则 -->
<!-- ================================================================================ -->
<!-- 检查文件中是否有标签 -->
<check level="error" class="org.scalastyle.file.FileTabChecker" enabled="true"></check>
<!-- 检查加号后面是否有空格 -->
<check level="error" class="org.scalastyle.scalariform.SpacesAfterPlusChecker" enabled="true"></check>
<!-- 检查加号前面是否有空格 -->
<check level="error" class="org.scalastyle.scalariform.SpacesBeforePlusChecker" enabled="true"></check>
<!-- 检查行尾没有空格 -->
<check level="error" class="org.scalastyle.file.WhitespaceEndOfLineChecker" enabled="true"></check>
<!-- 检查一行中的字符数 -->
<check level="error" class="org.scalastyle.file.FileLineLengthChecker" enabled="true">
<parameters>
<parameter name="maxLineLength"><![CDATA[100]]></parameter>
<parameter name="tabSize"><![CDATA[2]]></parameter>
<parameter name="ignoreImports">true</parameter>
</parameters>
</check>
<!-- 检查类名是否与正则表达式匹配 -->
<check level="error" class="org.scalastyle.scalariform.ClassNamesChecker" enabled="true">
<parameters>
<parameter name="regex"><![CDATA[[A-Z][A-Za-z]*]]></parameter>
</parameters>
</check>
<!-- 检查对象名称是否与正则表达式匹配 -->
<check level="error" class="org.scalastyle.scalariform.ObjectNamesChecker" enabled="true">
<parameters>
<parameter name="regex"><![CDATA[(config|[A-Z][A-Za-z]*)]]></parameter>
</parameters>
</check>
<!-- 检查包对象名是否与正则表达式匹配 -->
<check level="error" class="org.scalastyle.scalariform.PackageObjectNamesChecker" enabled="true">
<parameters>
<parameter name="regex"><![CDATA[^[a-z][A-Za-z]*$]]></parameter>
</parameters>
</check>
<!-- 检查方法的参数个数是否超过设置数量 -->
<check customId="argcount" level="error" class="org.scalastyle.scalariform.ParameterNumberChecker" enabled="true">
<parameters>
<parameter name="maxParameters"><![CDATA[10]]></parameter>
</parameters>
</check>
<!-- 检查类和对象是否定义了finalize()方法 -->
<check level="error" class="org.scalastyle.scalariform.NoFinalizeChecker" enabled="true"></check>
<!-- 检查类和对象在没有覆盖的情况下定义了相等(java.lang.object) -->
<check level="error" class="org.scalastyle.scalariform.CovariantEqualsChecker" enabled="true"></check>
<!-- 检查结构类型是否未被使用 -->
<check level="error" class="org.scalastyle.scalariform.StructuralTypeChecker" enabled="true"></check>
<!-- 检查如果使用长字符串,则使用大写字母 -->
<check level="error" class="org.scalastyle.scalariform.UppercaseLChecker" enabled="true"></check>
<!-- 检查if是否使用大括号 -->
<check level="error" class="org.scalastyle.scalariform.IfBraceChecker" enabled="true">
<parameters>
<parameter name="singleLineAllowed"><![CDATA[true]]></parameter>
<parameter name="doubleLineAllowed"><![CDATA[true]]></parameter>
</parameters>
</check>
<!-- 检查方法是否具有显式返回类型 -->
<check level="error" class="org.scalastyle.scalariform.PublicMethodsHaveTypeChecker" enabled="true"></check>
<!-- 检查文件是否以换行符结尾 -->
<check level="error" class="org.scalastyle.file.NewLineAtEofChecker" enabled="true"></check>
<!-- 检查是否使用非ASCII字符(Unicode字符) -->
<check customId="nonascii" level="error" class="org.scalastyle.scalariform.NonASCIICharacterChecker"
enabled="true"></check>
<!-- 检查在注释后是否有一个空格 -->
<check level="error" class="org.scalastyle.scalariform.SpaceAfterCommentStartChecker" enabled="true"></check>
<!-- 检查某些既定标记前是否有空间 -->
<check level="error" class="org.scalastyle.scalariform.EnsureSingleSpaceBeforeTokenChecker" enabled="true">
<parameters>
<parameter name="tokens">ARROW, EQUALS, ELSE, TRY, CATCH, FINALLY, LARROW, RARROW</parameter>
</parameters>
</check>
<!-- 检查某些既定标记后是否有空间 -->
<check level="error" class="org.scalastyle.scalariform.EnsureSingleSpaceAfterTokenChecker" enabled="true">
<parameters>
<parameter name="tokens">ARROW, EQUALS, COMMA, COLON, IF, ELSE, DO, WHILE, FOR, MATCH, TRY, CATCH, FINALLY,
LARROW, RARROW
</parameter>
</parameters>
</check>
<!-- 检查代码是否有 ??? 操作符 -->
<check level="error" class="org.scalastyle.scalariform.NotImplementedErrorUsage" enabled="true"></check>
<!-- 由于 SPARK-7977, 所有的 println 都应该由 '// scalastyle:off/on println' 包裹-->
<check customId="println" level="error" class="org.scalastyle.scalariform.TokenChecker" enabled="true">
<parameters>
<parameter name="regex">^println$</parameter>
</parameters>
<customMessage><![CDATA[确定要 println 吗? 如果是的话,需要用下面的代码段包裹:
// scalastyle:off println
println(...)
// scalastyle:on println]]></customMessage>
</check>
<!-- mutable.SynchronizedBuffer -->
<check customId="mutablesynchronizedbuffer" level="error" class="org.scalastyle.file.RegexChecker" enabled="true">
<parameters>
<parameter name="regex">mutable\\.SynchronizedBuffer</parameter>
</parameters>
<customMessage><![CDATA[
确定要使用 mutable.SynchronizedBuffer 吗? 大多数场景下,你应该使用
java.util.concurrent.ConcurrentLinkedQueue 来替代。
如果你必须使用 mutable.SynchronizedBuffer,使用下面的代码段来包裹:
// scalastyle:off mutablesynchronizedbuffer
mutable.SynchronizedBuffer[...]
// scalastyle:on mutablesynchronizedbuffer
]]></customMessage>
</check>
<!-- Class.forName -->
<check customId="classforname" level="error" class="org.scalastyle.file.RegexChecker" enabled="true">
<parameters>
<parameter name="regex">Class\\.forName</parameter>
</parameters>
<customMessage><![CDATA[
确定要使用 Class.forName 吗? 大多数场景下,你应该使用 Utils.classForName 来替代.
如果你必须使用 Class.forName,使用下面的代码段来包裹:
// scalastyle:off classforname
Class.forName(...)
// scalastyle:on classforname
]]></customMessage>
</check>
<!-- 检查正则表达式是否匹配 -->
<check customId="caselocale" level="error" class="org.scalastyle.file.RegexChecker" enabled="true">
<parameters>
<parameter name="regex">(\\.toUpperCase|\\.toLowerCase)(?!(\\(|\\(Locale.ROOT\\)))</parameter>
</parameters>
<customMessage><![CDATA[
确定要使用 toUpperCase or toLowerCase without the root locale ? 大多数场景下,你应该使用
toUpperCase(Locale.ROOT) or toLowerCase(Locale.ROOT) 来替代。
如果你必须使用 toUpperCase or toLowerCase without the root locale,使用下面的代码段来包裹:
// scalastyle:off caselocale
.toUpperCase
.toLowerCase
// scalastyle:on caselocale
]]></customMessage>
</check>
<!-- throw new Error -->
<check customId="throwerror" level="error" class="org.scalastyle.file.RegexChecker" enabled="true">
<parameters>
<parameter name="regex">throw new \\w+Error\\(</parameter>
</parameters>
<customMessage><![CDATA[
确定要这样抛出异常吗?大多数场景下,你应该使用精确的异常来替代。
如果你必须这样抛出异常,使用下面的代码段来包裹:
// scalastyle:off throwerror
throw new XXXError(...)
// scalastyle:on throwerror
]]></customMessage>
</check>
<!-- 由于 SPARK-9613, JavaConversions 应该替换成 JavaConverters -->
<check customId="javaconversions" level="error" class="org.scalastyle.scalariform.TokenChecker" enabled="true">
<parameters>
<parameter name="regex">JavaConversions</parameter>
</parameters>
<customMessage>不要去隐式导入 scala.collection.JavaConversions._ 了, 导入
scala.collection.JavaConverters._ 并且使用 .asScala / .asJava 方法
</customMessage>
</check>
<!-- extractOpt -->
<check customId="extractopt" level="error" class="org.scalastyle.scalariform.TokenChecker" enabled="true">
<parameters>
<parameter name="regex">extractOpt</parameter>
Scala 风格:一个文件中有多个类?