请收下这些kotlin开发必知必会的编码实践方式(代码片段)

上马定江山 上马定江山     2023-04-05     263

关键词:

任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写出人类可以理解的代码。— 马丁·福勒

目前来说,作为Kotlin开发者想必对一些常见的比较优秀的编程实践方式已经耳熟能详了吧;下面让我们,一起来巩固下日常开发中常见的Kotlin编码实践方式,温故而知新,尽管有些知识点非常简单,但请务必牢牢掌握,有些细节的东西也值得我们注意;本文笔者将从以下几个方面进行巩固复习,将配合大量示例代码辅助说明,可能会略显枯燥;

常量Constant实践方式

首先简单列举下Kotlin中常用的常量类型,接下来我们从两个方面来讨论下Kotlin常量的实践方式

  • 在顶层和伴随对象中定义常量
  • Java中访问Kotlin中的静态对象

允许的常量类型

Kotlin 只允许定义基本类型(数字类型、字符和布尔值)String类型的常量

让我们尝试定义一个自定义类型的常量。首先,让我们创建一个没有任何逻辑的空类

class TestClass 

然后我们在常量类型中去使用这个类

const val constantAtTopLevel = TestClass()

结果会发生什么?当然是报错啦,编译器会提示以下错误,告诉我们只允许基本类型和String类型

Const 'val' has type 'SimpleClass'. Only primitives and String are allowed

Constant 顶层声明

上述我们尝试定义的自定义类型常量也是在顶层进行声明的,值得注意的是注意 Kt 不会将文件与类匹配。在一个文件中,我们可以定义多个类。与 Java 不同,Kt不需要每个文件一个父类。每个文件可以有多个父类。

文件也可以有类之外的函数和变量。这些函数和变量可以直接访问。

让我们在刚才的文件中再创建一个常量:

const val CONSTANT_AT_TOP_LEVEL = "constant value"

现在,我们从另一个类中去访问它

class ConstantAtTopLevelTest 
    @Test
    fun whenAccessingConstantAtTopLevel_thenItWorks() 
        Assertions.assertThat(CONSTANT_AT_TOP_LEVEL).isEqualTo("constant value")
    

事实上,常量可以从任何类访问。如果我们将一个常量声明为私有的, 它就只能被同一个文件中的其他类访问。当我们想要在文件或整个应用程序中的类之间共享一些值的时候,顶级常量(top-level)是一个比较好的解决方案。 此外,当值与特定类无关时,使用顶级常量是一个很好的选择。

局限性

尽管声明一个顶级变量非常简单,但也需要注意下声明该类常量时出现的一些限制。如上所述,定义在文件顶层的常量可以被同一文件中的任何类访问,即便它是私有的。我们也不能限制该文件中特定类的可见性。因此可以得出的结论是,此类常量不与任何类相关联

此外,对于顶级常量,编译器会生成一个新类。为此,编译器创建了一个类,其原始文件的名称后缀为Kt。在上面的例子中,它是*ConstantAtTopLevelTestKt,其中原始文件名是ConstantAtTopLevelTest.kt*`

Constant 伴随对象声明

现在让我们在伴随对象中定义一个常量

class ConstantsBestPractices 
    companion object 
        const val CONSTANT_IN_COMPANION_OBJECT = "constant at in companion object"
    

之后,让我们从*ConstantInCompanionObjectTest*类访问它

class ConstantInCompanionObjectTest 
​
    @Test
    fun whenAccessingConstantInCompanionObject_thenItWorks() 
        Assertions.assertThat(CONSTANT_IN_COMPANION_OBJECT).isEqualTo("constant in companion object")
    

这个时候该字段是属于一个类的。所以当我们想将值与类相关联时,在伴随对象中定义常量是一个比较好的解决方案,我们通过类的上下文访问它。

Java 中访问的静态对象

现在来看下Java代码中的静态对象的可访问性。使用上述已经创建好的顶层常量和伴随对象中的常量,我们新建一个*AccessKotlinConstant* Java 类

public class AccessKotlinConstant 
    private String staticObjectFromTopLevel = ConstantPracticeKt.CONSTANT_AT_TOP_LEVEL;
    private String staticObjectFromCompanion = ConstantsPractices.CONSTANT_IN_COMPANION_OBJECT;

一方面,顶层声明的常量可以从 Java 访问,生成的类名后缀为Kt 另一方面,伴随对象常量可以通过类名直接访问

简化我们的函数

如何避免 for 循环

在日常开发中,我们会经常用到For 循环,它是命令式编程的一个很好的结构。但是,如果有一个函数可以为你完成这项工作,那么最好改用该函数,这样能让你的代码变得简洁易懂。下面就来谈谈For循环在一些特定环境下使用的替代的实践方式

  • 使用repeat
//最好不要
fun  main ()  
  for (i in 0 until 10)  
    println(i) 
   
 
​
//可以这样写
fun  main ()  
  repeat(10)  
    println(it) 
   

  • 使用forEach
// DON'T 
fun  main ()  
  val list = listOf( 1 , 2 , 3 , 4 , 5 , 6 ) 
  for (e in list)  
    println(e) 
   
 
​
// DO 
fun  main ()  
  listOf( 1 , 2 , 3 , 4 , 5 , 6 ).forEach  
    println(it) 
   

  • 使用Map
// DON'T 
fun  main ()  
  val list = listOf( 1 , 2 , 3 , 4 , 5 , 6 ) 
  val newList = mutableListOf< Int () 
  for (e in list)  
    newList.add(e * e) 
   
 
​
// DO 
fun  main ()  
  val list = listOf( 1 , 2 , 3 , 4 , 5 , 6 ) 
  valnewList = list.map  it * it  

…还有更多的功能可以用来消除对循环的需求,这里就需要开发者在实际运用场景自行斟酌。

使用高阶函数

所谓的高阶函数,简单来说就是使用函数作为参数或返回值的函数,上面使用的代码可能不是最简洁的写法。我们可以通过将函数引用传递给高阶函数来进一步缩短我们的代码。下面简单举个栗子:

fun  main () 
   val input = readLine()
  input?.let 
     val sentence = it.split( " " )
    sentence.map(String::length).also(::println)
  

String::length传递类型的 lambda 函数(String) -> Int::println传递类型的 lambda 函数(Int) -> Unit

扩展值

如果开发者必须在代码的多个位置使用相同的值,我们可以考虑使用扩展值,这样可以有效避免代码冗余。

// 返回 int 的扩展值:
// 第一个单斜杠的索引
 private val String.hostEndIndex: Int
    get () = indexOf( '/' , indexOf( "//" ) + 2 )
    fun  main () 
        val url = "https://jackytallow.com/@cybercoder.aj"
        val host = url.substring( 0 , url.hostEndIndex).substringAfter( "//" )
        val path = url.substring(url.hostEndIndex).substringBefore("?")
    

优化条件结构方法的返回

如果你有一个有条件地返回不同值的函数,而不是在条件结构的每一行中都有返回return,你可以将返回提取出来统一处理,这样会简洁一些。下面以斐波那契数列方法为例:

fun main () 
  println(fibo(6))

​
 fun fibo (n: Int) : Int 
   return  when (n) 
     0 -> 0 
    1 -> 1 
    else -> fibo(n - 1) + fibo(n - 2)
  

此外,我们还可以通过将函数代码块转换为单行表达式函数来继续改进这一点。

fun main () 
  println(fibo(6))

fun fibo (n: Int) : Int = when (n) 
   0 -> 0 
  1 -> 1 
  else -> fibo(n - 1) + fibo(n - 2)

灵活使用标准函数

Kotlin 中有 5 个主要的作用域函数可以利用:letalsoapply和。withrun,它们之间的区别相信大家已经非常熟悉了,下面分别谈谈它们日常开发中运用的基本场景,这些标准函数的出现旨在让我们的代码看起来更加优雅

let函数

let函数用比较官方的说法就是默认当前这个对象作为闭包的it参数,返回值为函数最后一行或者return

  • 通俗的来说,我们使用它来将一种对象类型转换为另一种对象类型,比如说使用StringBuilder并计算其长度

    val stringBuilder = StringBuilder()
    val numberOfCharacters = stringBuilder.let 
        it.append("这是一个转换方法")
        it.length
    
    
  • let 函数也可以用于绕过可能的空类型。

fun  main () 
   val age = readLine()?.toIntOrNull()
   age?.let 
    println( "你是$it岁" ); 
   ?: println( "输入错误!" ); 

letalso的不同之处在于返回类型会发生变化**

also函数

这接收一个对象并对其执行一些额外的任务。其实就是相当于给定一个对象,对该对象进行一些相关操作also返回它被调用的对象,所以当我们想在调用链上生成一些辅助逻辑时,使用also会很方便

fun  main () 
  Person(
    name = "JackyTallow" ,
    age = 23 ,
    gender = 'M'
   ).also  println(it) 

run函数

此函数与函数类似let,但这里传递的是对象引用 是this而不是it,通常我们可以这么理解,run与let的关联方式和apply与also的关联方式相同

  • 下面我们依旧使用StringBuilder并计算其长度,这里我们使用run函数
val message = StringBuilder()
val numberOfCharacters = message.run 
    length

  • 对于let,我们将对象实例称为it,但在这里,对象是lambda 内部的隐式this

同样的,我们可以使用与let相同的方法来处理可空性:

val message: String? = "hello there!"
val charactersInMessage = message?.run 
    "value was not null: $this"
 ?: "value was null"

apply函数

applyalso差不多,它会初始化一个对象,不同的是它有一个隐含的this,当你希望更改对象的属性或行为时使用此函数,最后再返回这个对象。

fun  main () 
   val me = Person().apply 
    name = "JackyTallow"
     age = 23
     gender = 'M'
   
  println(me)

  • 值得注意的是,我们也可以用apply来构建builder模式的对象
data class Teacher(var id: Int = 0, var name: String = "", var surname: String = "") 
    fun id(anId: Int): Teacher = apply  id = anId 
    fun name(aName: String): Teacher = apply  name = aName 
    fun surname(aSurname: String): Teacher = apply  surname = aSurname 

​
val teacher = Teacher()
    .id(1000)
    .name("张三")
    .surname("Spector")

with函数

当你想使用一个对象的某个属性/多个属性时使用这个函数。简单来说,它只是apply函数的语法糖

fun  main () 
   val me = with(Person()) 
     name = "JackyTallow"
     age = 23
     gender = 'M'
   
  println(me)

另一种看待它的方式是在逻辑上将对给定对象的多个属性调用方法进行分组,比如说我们的账户验证,或者相关账户名称验证操作

   with(bankAccount) 
    checkAuthorization(...)
    addPayee(...)
    makePayment(...)
   

运算符重载和中缀函数

运算符重载

我们可以在Kotlin的官方文档中找到运算符函数列表,在 Kotlin 中,+、- 和 * 等运算符链接到相应的函数,通过在你的类中提供这些函数,你可以在 DSL 中创建一些非常简洁的处理语法,这些函数在我们的代码中充当语法糖。下面只是简单使用了下示例:

fun  main () 
   val list = mutableListOf( 1 , 2 , 3 )
  (list.puls(4).forEach(::println))

​
 operator  fun  <T> MutableList <T>.plus (t: T ) : MutableList<T> 
   val newList = mutableListOf<T>().apply  addAll( this@plus ) 
  newList.add(t)
   return newList

上面是笔者简单手写了个plus函数,它是按照Kt源码中自带的plus函数的基础上进行修改的。不要滥用此功能,一般来说,仅在你的特定DSL中执行此操作

中缀函数

Kotlin 允许在不使用句点和括号的情况下调用某些函数,这些就被称之为中缀表示法,这样使得代码看起来更贴合自然语言,可以看到最常见的Map中的定义

map(
  1 to "one",
  2 to "two",
  3 to "three"
)

可以看到to特殊关键字就是一个利用中缀表示法并返回Pair<A, B> 的to()方法

通用标准函数库中的中缀函数

除了用于创建Pair<A, B> 实例的 to() 函数之外,还有一些其他函数被定义为中缀。 例如,各种数字类——Byte、Short、IntLong—— 都定义了按位函数and()、or()、shl()、shr()、ushr()xor(), 允许更多可读表达式:

val color = 0x123456
val red = (color and 0xff0000) shr 16
val green = (color and 0x00ff00) shr 8
val blue = (color and 0x0000ff) shr 0
  • Boolean类以类似的方式定义and()、or()xor( ) 逻辑函数:
if ((targetUser.isEnabled and !targetUser.isBlocked) or currentUser.admin) 
    // Do something if the current user is an Admin, or the target user is active

  • String类还将matchzip函数定义为中缀,允许一些易于阅读的代码
"Hello, World" matches "^Hello".toRegex()

在整个标准库中还可以找到一些其他中缀函数的示例,以上这些应该是日常开发中最常见的

自定义简单中缀函数

我们也可以编写属于自己的中缀函数,在为我们的应用程序编写领域特定语言时,允许DSL 代码更具可读性。很多开源库已经使用自定义函数并取得了很好的效果,比如说,mockito-kotlin库定义了一些中缀函数—— doAnswerdoReturndoThrow—— 它们都是用于定义模拟行为

要想编写自定义中缀函数,需要遵循以下三个规则:

  • 该函数要么在 class类上定义,要么是 class类的扩展方法

  • 该函数只接受一个参数

  • 该函数是使用infix关键字定义的

    下面笔者简单定义一个断言框架用来测试,在这其中定义自己的中缀函数

class Assertion<T>(private val target: T) 
    infix fun isEqualTo(other: T) 
        Assert.assertEquals(other, target)
    
​
    infix fun isDifferentFrom(other: T) 
        Assert.assertNotEquals(other, target)
    

是不是看起来很简单,通过使用infix关键字的存在我们可以编写如下代码

val result = Assertion(5)
result isEqualTo 5 
result isEqualTo 6 
result isDifferentFrom 5

这样是不是立马让这段代码变得更加清晰起来,更容易理解

注意一下,中缀函数也可以编写为现有类的扩展方法。这其实挺强大的,因为它允许我们扩充来自其他地方(包括标准库)的现有类以满足我们开发的需要。

例如,让我们向字符串添加一个函数,以提取与给定正则表达式匹配的所有子字符串:

infix fun String.substringMatches(regex: Regex): List<String> 
    return regex.findAll(this)
        .map  it.value 
        .toList()

​
 val matches = "a bc def" substringMatches ".*? ".toRegex()
    Assert.assertEquals(listOf("a ", "bc "), matches)

中缀函数的出现使得我们的代码变得更加清晰,更易于阅读

yield函数运用

关于yiled() 函数,我们首先要知道它是一个在Kotlin Coroutines上下文中使用的挂起函数;如果条件允许的话,它会将当前协程调度程序的线程(或线程池)让给其他协程运行

从日常开发角度出发,我们通常在构建序列和实现作业的协作式多任务处理两个方面中会使用到yield() 函数,下面我们来动手实践一下

构建序列

yiled() 最常见的用法之一就是用于构建序列,下面笔者将分别使用它来构建有限序列和无限序列,Let’s go

有限序列

假设我们想要构建一个有限的元音序列。对于如此短的序列,我们可以使用多个语句来产生单个元音值。让我们在Yield类中定义vowels() 函数

class Yield 
    fun vowels() = sequence 
        yield("a")
        yield("e")
        yield("i")
        yield("o")
        yield("u")
    

现在我们调用这个vowels方法对此序列进行迭代iterator

val client = Yield()
val vowelIterator = client.vowels().iterator()
while (vowelIterator.hasNext()) 
    println(vowelIterator.next())

在这个简单的场景中,关于有限序列需要注意的一件重要事情,在调用vowelIteratornext() 方法之前,我们应该始终使用hasNext() 方法检查序列中是否有下一个可用项

无限序列

使用yield() 的一个更实际的用例是构建无限序列。因此,让我们用它来生成斐波那契数列的项。为了构建这样一个序列,让我们编写一个fibonacci() 函数,它使用一个无限循环,在每次迭代中产生一个单项:

fun fibonacci() = sequence 
    var terms = Pair(0, 1)
    while (true) 
        yield(terms.first)
        terms = Pair(terms.second, terms.first + terms.second)
    

接下来,让我们通过对该序列使用迭代器来验证序列的前五项:

val client = Yield()
val fibonacciIterator = client.fibonacci().iterator()
var count = 5
while (count > 0) 
    println(fibonacciIterator.next())
    count--

对于以上这个无限序列,可以放宽对迭代器的hasNext() 方法调用,因为我们可以保证获得序列的下一个元素

协作式多任务处理

介绍已经说了yield() 是一个挂起函数,它允许当前调度的线程让给另一个协程运行,而在协作式多任务系统中,一个任务会自愿放弃以允许另一个作业执行,这也意味者,我们是不是可以使用yield() 实现协作式多任务处理

数字打印机

下面我们来实践下,实现一个简单的奇偶数字打印机,假设我们要打印低于特定阈值的所有数字

  • 使用AtomicInteger将当前值定义为0,并将阈值定义为常量整数值
val current = AtomicInteger(0)
val threshold = 10
  • 定义一个numberPrinter() 函数来协调数字的打印,这里笔者打算定义两个不同的作业来分而治之,一个用于打印偶数,另一个用于打印奇数,所以为了确保我们一直等到所有低于阈值的数字都被打印出来,这里将使用runBlocking
fun numberPrinter() = runBlocking 
    val eventNumberPrinter = ...
    val oddNumberPrinter = ...

  • 接下来将打印数字的任务委托给两个不同作业部分, 即evenNumberPrinteroddNumberPrinter

    • 首先先看看如何启动eventNumberPointer作业:

      val evenNumberPrinter = launch 
          while (current.get() < threshold) 
              if (current.get() % 2 == 0) 
                  println("$current is even")
                  current.incrementAndGet()
              
              yield()
          
      
      

      可以看到非常直观,仅在偶数的时候才打印当前值,然后使用了yield() 函数意味着,它需要明白与另一个可以打印奇数值的任务合作,所以它自愿让步了

    • 接下来,再看看oddNumberPrinter作业,除了只打印奇数的情况外,它本质上是相同的:

      val oddNumberPrinter = launch 
          while (current.get() < threshold) 
              if (current.get() % 2 != 0) 
                  println("$current is odd")
                  current.incrementAndGet()
              
              yield()
          
      
      
  • 最后,我们调用numberPrinter() 来打印数字,正如预期的那样,我们能够看到所有低于阈值的数字

0 is even
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd

综上我们通过构建序列和协作式多任务处理两种方式对yield() 函数进行简单实践运用

参考

作者:RainyJiang
链接:https://juejin.cn/post/7202970020233134140

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。


相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

二、源码解析合集


三、开源框架合集


欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

架构实践架构师必知必会的5种业界主流的架构风格

 【架构实践】架构师必知必会的5种业界主流的架构风格目录 【架构实践】架构师必知必会的5种业界主流的架构风格 查看详情

好奇?!elasticsearch25个必知必会的默认值

...紧:聊天记录中涉及“默认”关键词的讨论接近400多处。这些默认值对于架构选型、开发实战、运维排查性能问题等都有很好的借鉴价值,虽官方文档都有详细论述,但散落在各个角度。处于本能的好奇心,我认为非常有必要结... 查看详情

tcp/ip,必知必会的

...TCP拥塞控制 0前言本文整理了一些TCP/IP协议簇中需要必知必会的十大问题,既是面试高频问题,又是程序员必备基础素养。 1TCP/IP模型TCP/IP协议模型(TransmissionControlProtocol/InternetProtocol 查看详情

必知必会的设计原则——合成复用原则(代码片段)

 设计原则系列文章 必知必会的设计原则——单一职责原则必知必会的设计原则——开放封闭原则必知必会的设计原则——依赖倒置原则必知必会的设计原则——里氏替换原则必知必会的设计原则——接口隔离原则必知必... 查看详情

持续更新,建议收藏python必知必会的知识点,极大提升开发效率(代码片段)

问题本文主要介绍Python编程的一些必知必会的知识点,方便后续编程,提升效率。方法字符串转整数#字符串是普通整数a=int('1000')print(a)#1000#字符串是二进制b=int('1000',2)print(b)#8#整数转固定长度的二进制... 查看详情

持续更新,建议收藏python必知必会的知识点,极大提升开发效率(代码片段)

问题本文主要介绍Python编程的一些必知必会的知识点,方便后续编程,提升效率。方法整数列表join设有一个整数列表,实现连接所有整数形成一个字符串,如下:d=[1,2,3,4]print(''.join(d))很遗憾,上... 查看详情

elasticsearchelasticsearch25个必知必会的默认值

...xff1a;聊天记录中涉及“默认”关键词的讨论接近400多处。这些默认值对于架构选 查看详情

身为开发必知必会的linux:linux远程连接/命令的使用

系列文章目录🍑软件测试功能到自动化学习路线图,2022年最新版技术栈🍑软件测试01:从了解测试岗位职能和测试流程开始,附作业🍑软件测试02:6大实际案例手把手教你设计测试点🍑软件测试0... 查看详情

elasticsearch必知必会的干货知识二:es索引操作技巧(代码片段)

该系列上一篇文章《Elasticsearch必知必会的干货知识一:ES索引文档的CRUD》讲了如何进行index的增删改查,本篇则侧重讲解说明如何对index进行创建、更改、迁移、查询配置信息等。仅创建索引:PUTindexPUT/index添加字段设置(mappings... 查看详情

机器学习领域必知必会的12种概率分布(附python代码实现)

...a;机器之心机器学习开发者需要了解的12种概率分布,这些你都了解吗?机器学习有其独特的数学基础,我们用微积分来处理变化无限小的函数,并计算它们的变化;我们使用线性代数来处理计算过程;我... 查看详情

优秀android程序员必知必会的网络基础,面试心得体会

一.开发背景想要成为一名优秀的Android开发,你需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样。什么是HTTPS?HTTPS(基于安全套接字层的超文本传输协议或者是HTTPoverSSL)是一个Netscape开发的Web协议... 查看详情

10个必知必会的统计学问题

...?假设检验的内涵和步骤?这篇文章带你来看10个必知必会的统计学问题。正文来源:计量经济学1、问:自由度是什么?怎样确定?答:ÿ 查看详情

2020最新40k技能清单:聚焦java开发工程师必知必会的进阶知识!

在你身边可有这一些这样的事件现象已经工作两三年了,每个项目都会加班加点全力以赴去完成,薪资增长幅度却不如人意。听说年后离职的老同事,金三刚拿下高薪offer,年薪直奔50万了。由于现在的公司接触不到新技术,对... 查看详情

大数据必知必会的-linux命令(代码片段)

用户的创建和删除命令用户创建和密码设置useradd用户名passwd用户名useradditheima#创建新用户itheimapasswditheima#设置用户itheima密码用户删除user-r用户名userdel-ritheima#删除用户itheima权限管理命令文件权限概述Linux操作系统是多任务多用... 查看详情

大数据必知必会的-linux命令(代码片段)

用户的创建和删除命令用户创建和密码设置useradd用户名passwd用户名useradditheima#创建新用户itheimapasswditheima#设置用户itheima密码用户删除user-r用户名userdel-ritheima#删除用户itheima权限管理命令文件权限概述Linux操作系统是多任务多用... 查看详情

zookeeper必知必会的知识点

ZooKeeper是什么?ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接... 查看详情

jetty必知必会

导语如果是开发老鸟,请阅读快速入门,这已经足够。如果是新手,请阅读全文,这里有你想要的热部署,debug配置等内容,能够提高开发效率,避免浪费时间。简介jetty是一个应用服务器,类似于tomcat、resin,但是更轻量,尤其... 查看详情

大数据必知必会的-linux命令(代码片段)

终端命令格式command[-options][parameter]说明:command:命令名,相应功能的英文单词或单词的缩写[-options]:选项,可用来对命令进行控制,也可以省略parameter:传给命令的参数,可以是零个、一个或者多个显示文件列表命令ls是英文单词list的简... 查看详情