
English: 
Hi, my name is Nate and welcome to this tutorial on the Kotlin programming language. If
you're not familiar, Kotlin is a statically
type programming language developed by JetBrains.
It's been around since about 2011 and has
steadily increased in popularity ever since.
Today it's actually the primary development
language for Android and in this tutorial
we're going to move from basic topics like
setting up your first project up to more advanced
things like modeling data and working with
higher order functions. The goal for this
tutorial is to help you understand how the
work with Kotlin so that you can then take
that knowledge and apply it to building applications
across mobile, web and native code. So without
further ado, let's jump in and start building
our first Kotlin project.

Chinese: 
嗨，我的名字是Nate，欢迎使用Kotlin编程语言的本教程。如果
你不熟悉，Kotlin是一个静态的
由JetBrains开发的类型编程语言。
它自2011年左右开始出现并且已经存在
从那时起，人气逐渐增加。
今天它实际上是主要的发展
适用于Android和本教程的语言
我们将从基本话题转移到像
将您的第一个项目设置为更高级
像建模数据和使用的东西
高阶函数。这个目标
教程是帮助你了解如何
和Kotlin一起工作，这样你就可以服用了
知识并将其应用于构建应用程序
跨移动，网络和本机代码。所以没有
更进一步，让我们跳进去开始建设
我们的第一个Kotlin项目。

Chinese: 
我们要做的第一件事就是
是安装JetBrains IDE Intelijay这样的
我们可以在我们的开发中使用我们的Kotlin代码
机。首先要做的就是打开
浏览器并搜索它。杰伊
在这里，你应该看到一个下载链接和我们
可以点击直接进入
下载页面。现在我将继续努力
一台Mac，但在Windows上可以使用智能
和Linux一样。你也会注意到这里
有两种不同版本的情报。
有终极版和社区
版。终极版还有很多
我们需要的功能，也有付费
产品。社区版是支持性的
用于JVM开发和Android开发，
所以它非常适合我们想要看的东西
在本教程中。当你准备好了，继续吧
然后单击下载按钮
开始下载。下载完成后，

English: 
The first thing we're going to want to do
is to install JetBrains IDE Intelijay so that
we can work with our Kotlin code on our development
machine. The first thing to do is to open
up your browser and search for it. Until Jay
here, you should see a download link and we
can click on that to be taken directly to
the download page. Now I'll be working on
a Mac, but intelligent is available on windows
and Linux as well. You'll also notice here
that there are two different versions of intelligence.
There's the ultimate edition and the community
edition. The ultimate edition has a lot more
features that we need and there's also a paid
product. The community edition is supportive
for JVM development and Android development,
so it's perfect for what we want to look at
in this tutorial. When you're ready, go ahead
and click the download button and that should
start the download. Once the download is complete,

English: 
we'll get started on installing the IDE and
we'll take a look at hello and Kotlin. Now
that our downloads complete, we can go ahead
and onto the installer
and I'm Mac. We'll drag the application into
our applications folder which will start the
install process here for us. Once the files
have been transferred to your machine, we
can go ahead and start intelligent for the
first time to start the install process. In
this case, we want to do a fresh install,
so click that. Do not import settings and
hit okay.
Go ahead and accept the privacy policy. Hit
continue. Now here you can choose your theme.
I'll choose the dark theme. Go ahead with
the standard and tell the J key settings here
and we'll go ahead and click next through
to finish the setup process and then we'll
finally launch intelligent IDE community edition.

Chinese: 
我们将开始安装IDE和
我们来看看你好和Kotlin。现在
我们的下载完成后，我们可以继续
并安装到安装程序上
而我是Mac。我们将应用程序拖入
我们的应用程序文件夹将启动
在这里为我们安装流程。一旦文件
我们已经转移到你的机器上了
可以继续前进并开始智能化
第一次开始安装过程。在
在这种情况下，我们想要进行全新安装，
所以点击它。不要导入设置和
好的。
继续并接受隐私政策。击中
继续。现在，您可以选择主题。
我会选择黑暗的主题。先继续
标准并在此处告诉J键设置
我们将继续点击下一步
完成设置过程然后我们会
最后推出智能IDE社区版。

Chinese: 
接下来要做的就是创造我们的
第一个Kotlin项目在智能方面。
所以要做到这一点，我们将点击创建新项目。
现在在这个面板的左侧，我们将
看到许多不同的项目模板
选择，因为我们将成为
了解Kotlin。我们想确保
我们选择了Kotlin模板。
现在，在这里，有许多不同
Collin项目类型，我们可以选择。
顶部的默认值是Kotlin模块
对于JVM目标，所以这将是一种
一个标准，只是Kotlin项目，可以
定位JVM。我没有其他任何补充
它。其他的例子是，你知道Caitlyn
我教过的Java脚本目标模块
在原生目标或Android或iOS中
移动目标。所有这些都很有趣
但更先进。为此，我们想要
坚持基础，所以我们会确保

English: 
The next thing that want to do is create our
first Kotlin project here in intelligence.
So to do that we'll click on create new project.
Now over on the left side of this panel, we'll
see a number of different project templates
to choose from because we are going to be
learning about Kotlin. We want to make sure
that we have selected the Kotlin template.
Now within this, there are a number of different
Collin project types that we can choose from.
The default here at the top is a Kotlin module
for a JVM target, so this would be sort of
a standard, just Kotlin project that could
target a the JVM. I have nothing else added
to it. Other examples would be, you know Caitlyn
module for a Java script target or I taught
in the native targeted or an Android or iOS
mobile target. So all of those are interesting
but more advanced. For this, we want to just
stick with the basics so we will make sure

Chinese: 
我们为JVM选择了Kotlin模块
目标并继续下一步。然后我们
我想确保我们为项目命名
有意义的事。所以在这种情况下，让我们来吧
叫它问好凯特琳。我们会确保这一点
我们的项目位置已设定然后我们将
继续选择完成。
现在我们有一个空的Kotlin项目。让我们
首先添加我们的第一个公共文件
我们可以写一个简单的hello world例子。
那样做吧。我们来到左边
在这里我们有项目小组
智能。你会看到我们的顶部
我们的你好Collin模块。如果我们扩大那个
我们可以看到我们有一个源目录
但它目前是空的。那就对了。点击
在源代码上，转到新的然后是Caitlyn文件

English: 
that we have selected Kotlin module for JVM
target and go ahead and hit next. Then we
want to make sure that we name our project
something meaningful. So in this case, let's
call it hello Caitlyn. We'll make sure that
our project location is set and then we'll
go ahead and select finish.
Now we have an empty Kotlin project. Let's
start by adding our first common file so that
we can write a simple hello world example.
So do that. We'll come over here to the left
and here we have the project panel within
intelligent. You'll see at the top we have
our hello Collin module. If we expand that
we can see that we have a source directory
but it's currently empty. That's right. Click
on source, go to new and then Caitlyn file

Chinese: 
我们班。在这里我们打算输入main
对于我们文件的名称然后我们会
将此保留为文件，以便我们可以创建我们的文件
主要点KT文件。现在我们可以开始了
在我们的主要部分写我们的主要功能
dotK T文件。所以开始我们会输入乐趣
缅因州，没有参数，然后我们可以打字
打印Ellen括号。
你好科林。从那里你会看到现在
我们有这个小绿箭智能
认识到这是一个可执行的主要内容
在这个呃你好Caitlyn模块中的功能。
所以我们实际上可以继续运行它。
我们将选择运行主KT并且这将采取
第二步继续建设项目。
然后我们将在此处获取输出窗口
在底部，你可以看到我们有
你好科林。现在是一个额外快速有趣的事实

English: 
our class. And here we're going to type main
for the name of our file and then we will
leave this as file so that we can create our
main dot KT file. Now we can get started by
writing our main function here in our main
dotK T file. So to start we'll type in fun
Maine, no parameters and then we can type
print Ellen parentheses.
Hello Collin. And from there you'll see now
that we have this little green arrow intelligent
recognizes that this is an executable main
function within this uh hello Caitlyn module.
So we can actually go ahead and run this.
We'll select to run main KT and that'll take
a second to go ahead and build the project.
And then we will get our output window here
at the bottom and you can see that we have
hello Collin. Now one extra quick fun fact

Chinese: 
在这里告诉杰伊带来一些现场直播
模板构建它。这意味着你可以
输入内容，它将知道如何完成
那并为我们自动生成一些代码。所以
我们可以开始输入缅因州，然后按Enter键
它会自动生成一个主
对我们有用。然后我们可以自由填补
在我们的问候Caitlyn文本中。
真棒。你刚刚编写了第一个程序
在Kotlin。现在让我们潜入并开始实际
学习语言入门。让我们
看看如何在Kotlin中定义变量。
现在有两种类型的变量。在科特林
我们可以定义可变变量，可以
重新分配他们的价值观。这些是宣布的
使用VAR关键字。或者我们可以定义本地

English: 
here and tell Jay comes with a number of live
templates built it. This means that you can
type something and it will know how to complete
that and auto-generate some code for us. So
we can start typing Maine and then hit enter
and it will automatically generate a main
function for us. And then we are free to fill
in with our, hello Caitlyn text.
Awesome. You've just written your first program
in Kotlin. Now let's dive in and start actually
learning the language to get started. Let's
look at how you can define variables in Kotlin.
Now there's two types of variables. In Kotlin
we can define mutable variables, which can
have their values reassigned. Those are declared
using the VAR keyword. Or we can define local

Chinese: 
只读变量，可以有它们的
仅在定义这些值时分配的值
使用vow关键字。所以要定义一个变量，
我们可以使用我们选择的关键字。所以
这种情况我们使用誓言，然后我们将定义
名称，然后我们需要指出该类型。
在这种情况下，我会说一个类型字符串然后
你可以使用等于然后你可以分配
此变量的值。所以在这种情况下
我已经定义了一个名为name of type的变量
串。
然后我分配了字符串文字
Nate到那个变量。现在，就像我提到的那样，
发誓我们分配一次变量，这意味着
只有在分配了值后才会被读取
它。所以，如果我试图更新名称
这个，我们会看到我们得到一个错误。那

English: 
read only variables, which can have their
value assigned only once these are defined
using the vow keyword. So to define a variable,
we can use the keyword of our choice. So in
this case we use vow, then we'll define the
name and then we need to indicate that type.
In this case I'll say a type string and then
you can use an equals and then you can assign
the value to this variable. So in this case
I've defined a variable called name of type
string.
And then I have assigned the string literal
Nate to that variable. Now, like I mentioned,
vow our assign once variables, meaning this
is read only once it has a value assigned
to it. So if I tried to update the name of
this, we'll see that we get an error. That

English: 
area says vow cannot be reassigned. So this
is our indicator that if we need to be able
to update the value of our variable, we're
not going to be able to use a vow. Instead
we can use a VAR. Now VAR variables can be
reassigned as many times as you want. So as
soon as I updated that keyword, now I can
update the value of our name variable. And
then if we want to use that variable, we can
pass that in to the print function here. And
if we then run our main function, well now
see the output value of that variable at this
time is blank because we had reassigned it.
If we remove that reassignment, well now see
that we get this little underlying saying
variables never modified and can actually
be declared immutable instead using vow. So

Chinese: 
区域说誓言不能重新分配。所以这
是我们的指标，如果我们需要能够
为了更新变量的值，我们是
不能使用誓言。代替
我们可以使用VAR。现在VAR变量可以
根据需要重新分配多次。这样
我更新了该关键字，现在我可以
更新我们的name变量的值。和
那么如果我们想要使用那个变量，我们就可以
将其传递给打印功能。和
如果我们现在运行我们的主要功能
在此查看该变量的输出值
时间是空白的，因为我们已经重新分配了它。
如果我们删除那个重新分配，现在看看
我们得到这个有点潜在的说法
变量从未修改过，实际上可以
使用誓言声明不可变。所以

Chinese: 
这很好，IDE为我们提供了帮助
暗示。所以在这种情况下我们会回到誓言。
现在，如果我们再次重新运行，那么
现在看到我的名字被打印出来了
控制台和这个例子我们正在使用本地
变量，意思是我们的变量
定义在本地可用
目前的范围。所以在这种情况下它是可用的
仅在我们定义的主要功能中。
现在在Kotlin你可以实际声明变量
在任何类型的封闭功能之外。
我们的课，你所要做的就是宣布一个
Kotlin文件中的变量。所以在这
我们将变量名称移到了外面
主要功能进入主要点。凯特。
他提到了像这样定义的文件变量
作为顶级变量。而你现在看到了
我们把它移到主要的外面

English: 
this is nice that the IDE gives us that helpful
hint. So in this case we'll go back to a vow.
And now if we rerun this once again, well
now see that my name was printed out to the
console and this example we're using a local
variable, meaning that the variable that we
have defined is available locally within the
current scope. So in this case it's available
only within the main function we have defined.
Now in Kotlin you can actually declare variables
outside of any type of enclosing function.
Our class, all you have to do is declare a
variable within a Kotlin file. So in this
case we've moved our variable name outside
of the main function into the main dot. Kate.
He file variables defined like this are referred
to as top level variables. And you see now
that we've moved this outside of the main

Chinese: 
功能，我们仍然可以运行它和我们的变量
仍然完全有效。
顶级变量可以使用
像一个局部变量。所以我们得到了罚款
一个额外的变量。这次我们会说
类型字符串的VAR问候语等于你好。
我们现在有一个公开的顶级
变量称为问候语。所以，如果我们想要的话
来到这里并打印出一个问候语
在名字之前，我们可以通过打电话来做到这一点
打印线和传递问候。我们可以
也修改那个问候，因为这是
一个可变变量，然后我们打印出来
这个新值，我们将看到该消息
已经改变。

English: 
function, we can still run it and our variable
is still completely valid.
Top level variables can be worked with just
like a local variable. So we get a fine and
an additional variable. This time we'll say
VAR greeting of type string equals hello.
We now have a publicly available top level
variable called greeting. So now if we wanted
to come down here and print out a greeting
before the name, we could do that by calling
print line and passing in greeting. We can
also modify that greeting because this is
a mutable variable and if we then print out
this new value, we will see that the message
has changed.

Chinese: 
所以当我们在这里跑步时，我们现在应该看到
你好，Nate。然后你好伙伴，让我们采取一个
仔细看看如何定义变量类型。
所以在定义我们的变量时，在两种情况下
我们使用凭证或VAR关键字和
然后我们有变量名。这两个
是必须的。下一步我们有结肠
然后是类型。所以在这种情况下我们有
字符串的类型，然后我们分配我们的
值。一个有趣的区别
Java和Kotlin是Kotlin中的类型
非空。默认情况下，这意味着那里
字符串和字符串之间的明显区别
一个可以为空的字符串。现在这看起来是什么
喜欢在练习？那么在这种情况下是因为
类型是非全部默认名称是nano
串。所以，如果我尝试分配一个无值
对此，我们实际上会得到一个错误

English: 
So when we hit run here, we should now see
hello Nate. And then hi mate, let's take a
closer look at how variable types are defined.
So in defining our variables, in both cases
we use either the voucher or VAR keyword and
then we have the variable name. Both of these
are must haves. Next step we have the colon
and then the type. So in this case we have
the type of string and then we assign our
value. One interesting difference between
Java and Kotlin is that types in Kotlin are
non null. By default this means that there
is a distinct difference between string and
a nullable string. Now what does this look
like in practice? Well in this case because
types are non all by default name is a nano
string. So if I tried to assign a no value
to this, we'll actually get an error and it

English: 
will hopefully say no, cannot be a value of
a non Knoll type string. So if you want to
actually have no as a valid value for your
variable, you need to add a question Mark
after that string value. This indicates that
now named as a knowable string. And I can
assign no or I can go ahead and sign an actual
value. So let's look at how we could use this
with the greeting variable.
So if we make greeting a knowable variable,
we can come down here and we'll go ahead and
print out the default greeting value. We'll
print out the name and then we'll see that
we can modify the value of greeting to null.
And then we can go ahead and print out these
values ones again and we can then see that
greeting has been updated. And when we try
to print that out, it actually recognizes
that it's no and prints that out to the console

Chinese: 
希望说不，不能是一个价值
一个非Knoll类型的字符串。所以，如果你想
实际上没有作为你的有效价值
变量，你需要添加一个问号Mark
在那个字符串值之后。这表明了
现在命名为可知字符串。我可以
分配否，或者我可以继续并签署实际的
值。那么让我们来看看我们如何使用它
与问候变量。
所以如果我们问一个可知的变量，
我们可以来这里，我们会继续前进
打印出默认的问候语值。好
打印出名称然后我们就会看到
我们可以将greeting的值修改为null。
然后我们可以继续打印出来
重新评估，我们可以看到
问候语已更新。当我们尝试
要打印出来，它实际上是认可的
它没有，并打印到控制台

English: 
for us. So let's look at how we can actually
simplify the declaration of our variables.
I mentioned that vow or bar as well as the
name are mandatory. However, Kotlin supports
type inferences on variables and properties.
What does this mean? Well, this means that
Kotlin can recognize what type the value is
that we're trying to assign to the variable
and if it can figure that out, we can actually
omit a type declaration of the variable.
So in this case we could actually remove the
colon and string and the name variable will
still be of type string. Now we can do the
same for our greeting variable so we can remove

Chinese: 
为了我们。那么让我们看看我们如何实际
简化变量的声明。
我提到誓言或酒吧以及
名称是强制性的。但是，Kotlin支持
对变量和属性进行类型推断。
这是什么意思？嗯，这意味着
Kotlin可以识别出价值的类型
我们正试图分配给变量
如果它可以解决这个问题，我们实际上可以
省略变量的类型声明。
所以在这种情况下我们实际上可以删除
冒号和字符串以及名称变量将
仍然是字符串类型。现在我们可以做到了
我们的问候变量也一样，所以我们可以删除

English: 
this. But if we come back down here and tried
to assign knowl to greeting will get an error.
No, it cannot be a value of non node type
string. So why is this? Well again, because
types are non nano by default and Kotlin and
we are assigning a nano string literal to
greeting the compiler. In first the greeting
is meant to be a non null string. So if you
want to have a knowable string you might try
and just assign no. However we get a warning
saying implicit nothing type. This is because
greeting now cannot really be inferred. It
doesn't know what is a null type of. So in
this case we will need to go ahead and specify
a knowable.

Chinese: 
这个。但是，如果我们回到这里尝试
将问题分配给问候语将会出错。
不，它不能是非节点类型的值
串。那么为什么呢？好吧，因为
默认类型是非纳米和Kotlin和
我们正在分配一个纳米字符串文字
问候编译器。在第一次问候
意味着是非空字符串。所以，如果你
想要有一个可知的字符串，你可能会尝试
并且只分配否。但是我们收到警告
说隐含的任何类型。这是因为
现在问候不能真正推断出来。它
不知道什么是null类型。所以
在这种情况下，我们需要继续并指定
一个可知的。

English: 
Now down here we can assign Knowlton greeting
or we could assign an actual greeting. Now
that we've taken a look at how to create variables
and how the type system works, let's introduce
some basic control flow and we'll do this
by working with the nullable string variable
of greeting. So let's go ahead and remove
these values. Now let's say that we only want
to print out the value of greeting if it's
not no. So we could do that in a couple different
ways. The first one we'll look at is using
an if statement, if statements in Kotlin work
very much the same way as in Java. So we'll
use the if keyword followed by parentheses,
we use greeting. In this case we want to say
if greeting is not no printed out, so we can
say not equal to know and we'll finish it
off with curly braces.

Chinese: 
现在，我们可以分配Knowlton问候语
或者我们可以指定一个真实的问候语现在
我们已经看过如何创建变量
以及类型系统如何工作，让我们来介绍一下
一些基本的控制流程，我们会这样做
通过使用可空字符串变量
问候。所以让我们继续前进并删除
这些价值观。现在让我们说我们只想要
打印出问候的价值，如果是的话
不，不。所以我们可以在几个不同的地方做到这一点
方法。我们将看到的第一个是使用
if语句，如果Kotlin的陈述有效
与Java中的方式非常相似。所以我们会
使用if关键字后跟括号，
我们用问候语。在这种情况下，我们想说
如果问候语没有打印出来，那么我们就可以了
说不等于知道，我们会完成它
用花括号。

English: 
And then if we move our print statement within
that, if conditional when we run this, we
should now have no greeting printed out. And
sure enough we see that just the name is printed
and if we modified the value of greeting to
be non null and then rerun this, we'll now
see that we have our greeting. Now what if
we wanted to add and else claws? So just like
Java, we could add the else, we can add curly
braces again. And so here we could define
a default greeting of hi. So now if we run
this once again, greeting will be normal and
so we should see the default high value. Now
another means of control flow within Kotlin
is the when statement. The Wednesday mint
is very similar to a switch statement in Java.

Chinese: 
如果我们在其中移动我们的print语句
那，如果我们运行这个条件的条件，我们
现在应该没有打印出问候语。和
我们确实看到只打印了这个名字
如果我们将问候语的值修改为
非空，然后重新运行，我们现在
看到我们有问候。现在如果
我们想要添加和其他爪子？所以就像
Java，我们可以添加else，我们可以添加卷曲
再次支撑。所以我们可以在这里定义
一个默认的问候语。所以现在如果我们跑了
再一次，问候将是正常的
所以我们应该看到默认的高值。现在
Kotlin内的另一种控制流程
是什么时候陈述。周三薄荷
与Java中的switch语句非常相似。

English: 
So to create that we can come down and use
the when keyword and then print the CS.
We didn't want to pass end to this, the value
that we want to check and switch on depending
on its value. So in this case we'll pass in
grieving followed by curly braces. Now within
this block we can define each value that we
want to act on differently. So in this case
we can say no. And then to define what action
to take, we use an arrow and then we'll say
print line, hi. And then we can define and
else case here. And this will act as the default
if none of the values above are matched. So
this case we will print out the value of greeting
on its own.

Chinese: 
所以要创造我们可以下来使用
when关键字然后打印CS。
我们不希望传递到这个，价值
我们想要检查和打开依赖
它的价值。所以在这种情况下我们会传入
悲伤，然后是花括号。现在在
这个块我们可以定义我们的每个值
想采取不同的行动。所以在这种情况下
我们可以说不。然后定义什么动作
采取，我们使用箭头，然后我们会说
打印线，嗨。然后我们可以定义和
别的情况在这里。这将作为默认值
如果上述值均不匹配。所以
在这种情况下，我们将打印出问候的价值
在其自己的。

English: 
So now if we run this, we should see high
printed out because greeting is still not.
And once again if we update greeting to be
some other value and rerun, we'll see that
the branch of the, when statement is hit and
we are printing out the value of treating.
So these are two of the basic ways in which
you can manipulate control flow within Kotlin.
Now we just saw how if and when can we use
as statements to take different actions based
on some checked value if and when can also
be used as expressions to assign a value depending
on that, those logical conditions. So let's
take a look at how we could use an expression
to assign a value to a local variable. So
let's go down here and type vow greeting to

Chinese: 
所以现在如果我们运行它，我们应该看到高
打印出来因为问候仍然没有。
如果我们更新问候，再一次
其他一些价值并重新运行，我们会看到
当声明被击中时的分支
我们正在印刷治疗的价值。
所以这些是两种基本方式
你可以在Kotlin中操纵控制流程。
现在我们看看我们是否以及何时可以使用
作为采取不同行动的陈述
在某些检查值上，如果和何时也可以
用作表达式来赋值依赖
在那，那些逻辑条件。那么我们
看看我们如何使用表达式
为局部变量赋值。所以
让我们到这里来打字誓言

English: 
print. I can say equals. Now if the greeting
variable in our top level declaration is non
no, then we want to go ahead and stick with
that.
So we can say if greeting does not equal null,
then we want to assign greeting to the new
greeting to print variable. Otherwise we want
to say hi and then we'll update our print
line to use the local variable. Now when we
print this out, we should see the ELs branch
of high being printed out. This is because
the top level variable is currently no. If
we modify this to pass in a greeting. Now
if greeting does not equal null or return

Chinese: 
打印。我可以说平等。现在如果问候
我们的顶级声明中的变量是非变量
不，那么我们想继续坚持下去
那。
所以我们可以说问候语是否等于null，
然后我们想要给新人分配问候语
问候打印变量。否则我们想要
打个招呼，然后我们会更新我们的印刷品
行使用局部变量。现在我们的时候
打印出来，我们应该看到ELs分支
被打印出来的。这是因为
顶级变量目前没有。如果
我们修改这个以传递问候语。现在
如果问候语不等于null或返回

Chinese: 
是的，我们会看到你好打印出来
代替。所以，如果我们想分配不同的
变量的值，取决于是否
或不是某些东西是正常的或其他一些逻辑
检查，我们可以使用一个表达式。然而，
如果需要，我们也可以使用when表达式
它。所以我们可以说我们什么时候会再次通过
在这里一次又一次地对待我们将使用我们的号码
价值作为第一次检查，如果不是，我们会
继续前进并返回高位。否则我们会
继续并返回原来的问候语
值。所以现在有了这个，当表达是
说是为问候分配高值
打印。如果问候就知道了。同样地

English: 
true and we'll see that hello is printed out
instead. So if we want to assign different
values to a variable, depending on whether
or not something is normal or some other logical
check, we could use an expression. However,
we can also use a when expression if we want
it. So we can say when, and again, we'll pass
in treating here and again we'll use our no
value as the first check and if it's no, we'll
go ahead and return high. Otherwise we'll
go ahead and return the original greeting
value. So now with this, when expression is
saying is assign the value of high to greeting
to print. If greeting is know. And likewise

English: 
if greeting is nominal, go ahead and assign
that value to the new greeting to print variable.
So if we run this one more time, we should
see high because grieving is null.
And if we assign that value to greeting and
rerun, we'll see that updated value of hello.
So again, like the if expression a when expression
can be used to assign a value to a variable
depending on that input value that it's checking
to start understanding functions in top line.
Let's look at this example. Within this example,
we actually are using two different functions.
We have our main function and then we're also
using the print LN function as well. So let's
take a look at how we can define our own new
function. We'll start by clicking here and

Chinese: 
如果问候是名义上的，请继续并分配
该值为新问候打印变量。
因此，如果我们再运行一​​次，我们就应该这样做
看到高，因为悲伤是空的。
如果我们将这个值分配给问候和
重新运行，我们将看到你好的更新值。
所以再次，就像if表达式一样表达式
可用于为变量赋值
取决于它正在检查的输入值
开始理解顶线中的功能。
我们来看看这个例子。在这个例子中，
我们实际上使用两种不同的功能。
我们有主要功能，然后我们也是
使用打印LN功能。那么我们
看看我们如何定义自己的新东西
功能。我们先点击这里开始吧

Chinese: 
我们将定义正在进行的新功能
返回我们要打印的字符串
到控制台。所以第一件事就是
定义任何函数时都要使用
有趣的关键字这表明我们要走了
定义一个新功能。
然后我们要指定函数名称。
所以我打电话给这个函数，问候，
然后你想要打开它
和封闭的括号。在此我们
实际上可以定义任何函数参数。
现在我们要跳过任何功能
参数，我们想要定义我们的回报
输入此功能。所以与变量类似，
我们可以使用冒号定义返回类型。
然后是这种情况下字符串的类型。和
然后我们会做开放和闭合的花括号。
现在像在Java中我们可以定义返回

English: 
we'll define the new function that is going
to return this string that we want to print
out to the console. So the first thing to
do when defining any function is to use the
fun keyword. This denotes that we are going
to define a new function.
Then we want to specify the function name.
So I'm going to call this function, get greeting,
and then you want to follow that up with open
and closed parentheses. And within this we
can actually define any function parameters.
Now for now we're going to skip any function
parameters and we want to define our return
type for this function. So similarly to variables,
we can define a return type by using a colon.
And then the type in this case string. And
then we'll do open and closed curly braces.
Now like in Java we can define the return

Chinese: 
说回报的价值。然后在这种情况下
我会跟Kotlin打招呼。所以现在我们有了
函数叫做问候这个绿色到
返回字符串。你好Caitlyn。如果我们想要
然后调用该函数，我们可以这样做
通过打开和关闭来调用问候语
括弧。
这看起来应该与你的非常相似
熟悉和调用Java的方法。
现在，如果我们运行代码，我们将看到打印
声明。我们会看到第一个，你好
世界。第二个。你好科林。所以
你可能注意到的一件事是
我们的演出问候功能，我们是回归
流的类型。但是，在我们的主要功能
没有指定返回类型。那么为什么呢
这个？让我们通过一个例子来说明这一点。

English: 
value by saying return. And then in this case
I'll say hello Kotlin. So now we have the
function called get greeting this green to
return the string. Hello Caitlyn. If we want
to then invoke that function, we can do so
by calling get greeting with open and closed
parentheses.
This should look very similar to what you're
familiar with and calling methods from Java.
And now if we run our code, we'll see to print
statements. We'll see the first one, hello
world. And the second one. Hello Collin. So
one thing you may have noticed is that in
our gig greeting function, we're the return
type of stream. However, in our main function
there's no return type specified. So why is
this? Well let's illustrate this by an example.

English: 
Let's write a function called say hello. So
again we'll use the fun keyword and it will
maim it. Say hello, no parameter values. And
then we're going to declare this as returning
type unit unit. And Kotlin is essentially
the absence of any useful type. It's similar
to saying this returns nothing useful. And
the reason we're going to use unit in this
case is because we don't want to return anything.
We're going to simply print out our get greeting
functions, return value, so we can then call
say hello. And you'll notice up here that
unit is underlined and it's giving us this
message that says redundant unit return type.
Basically what this is saying is that if you
have a function that returns unit, that is
to say if you have a function that doesn't

Chinese: 
让我们写一个叫做hello的函数。所以
再次，我们将使用fun关键字，它会
伤害它。打个招呼，没有参数值。和
然后我们要宣布这是回归
单位单位。而Kotlin本质上是
没有任何有用的类型。它很相似
说这个没有用。和
我们之所以要在这里使用单位
这是因为我们不想退货。
我们打算简单地打印出问候语
函数，返回值，所以我们可以调用
问好。你会在这里注意到的
单位有下划线，它给了我们这个
表示冗余单元返回类型的消息。
基本上这是说，如果你
有一个返回单位的功能，即
如果你有一个没有的功能

English: 
return anything useful, you can omit that
type value. So we can actually remove unit
from our say hello function and this is perfectly
valid. So that's why in our main function,
we also don't have the return type specified.
Aside from the rules around unit return types,
return types or functions work very similarly
to how you would define them and treat them
for variables or properties. So for example,
if we wanted to return a Knoll string from
our get greeting potion, we would modify the
return type to be a nullable string and then
we could return note in our return statement.
Additionally, functions support type inference
as well. So in our get greeting example here

Chinese: 
返回任何有用的东西，你可以省略它
类型值。所以我们实际上可以删除单位
从我们说你好的功能，这是完美的
有效。这就是为什么在我们的主要功能中，
我们也没有指定返回类型。
除了单位回报类型的规则，
返回类型或函数非常相似
如何定义它们并对待它们
对于变量或属性。所以，例如，
如果我们想从中返回一个Knoll字符串
我们得到问候药水，我们会修改
返回类型为可以为空的字符串然后
我们可以在退货声明中返回注释。
此外，函数支持类型推断
同样。所以在我们的问候示例中

English: 
we are returning a single string literal,
in which case we could actually simplify this
to a single expression. We could remove the
curly braces and add an equals and then the
string literal after that. So this is what's
known as a single expression function because
the entire function definition is now in a
single expression. And now this is where the
title inference comes into play. Again, because
the compiler understands this single expression
function definition and it knows that it's
always going to return a string. We can actually
remove the explicit return type. Now our get
greeting is extremely simple and is functionally
equivalent to the previous definition. So
if we run our code, once again, we'll see
that we now have our three different print
statements. You might be noticing a theme

Chinese: 
我们返回一个字符串文字，
在这种情况下，我们可以实际简化这一点
一个表达式。我们可以删除
花括号并添加一个等于然后
之后的字符串文字。所以这是什么
称为单表达式函数，因为
现在整个函数定义都在
单一表达。现在这就是了
标题推断发挥作用。再次，因为
编译器理解这个单个表达式
函数定义，它知道它是
总是要返回一个字符串。我们其实可以
删除显式返回类型。现在我们得到
问候非常简单，功能也很简单
相当于之前的定义。所以
如果我们再次运行我们的代码，我们会看到
我们现在有三种不同的印刷品
声明。您可能会注意到一个主题

Chinese: 
Kotlin在这里允许我们减少金额
我们需要编写的代码来获得等价物
功能。这是一个将要裁剪的主题
当你开始学习时，越来越多
语言。
现在让我们来看看我们如何定义
功能参数。在我们开始之前，
让我们清理一下我们的代码。所以我们会
从我们的主要功能中删除所有内容
我们将继续并删除现有的
我们一直在使用的功能示例。
再一次，我们要定义一个函数
命名为打招呼并开始打印
出。你好科林。现在这就像
我们以前见过，但如果我们想要的话
改变我们问候的事情？
所以，不要跟科林打招呼，也许我们

English: 
here of Kotlin allowing us to reduce the amount
of code we need to write to get the equivalent
functionality. This is a theme that will crop
up more and more as you start to learn the
language.
Now let's take a look at how we can define
function parameters. Now before we get started,
let's clean up our code a little bit. So we'll
remove everything from our main function and
we're going to go ahead and remove the existing
function examples we've been working with.
So once again, we're gonna define a function
named say hello and to start it will print
out. Hello Collin. Now this is exactly like
we have seen before, but what if we wanted
to change the thing that we were greeting?
So instead of saying hello Collin, maybe we

Chinese: 
想要问好世界或你好伙伴，或者
你好约翰。那我们怎么做呢？好
这就是函数参数的来源
玩。所以要定义一个函数参数，我们将
在函数之后进入括号内
name，我们将使用表示法来定义它
参数名称冒号，参数
类型。所以在这种情况下我们会说项目
两个克里特岛作为我们的参数名称冒号。和
那么我们希望这是一个字符串值
我们正在通过它。现在有晚餐功能，
我们可以说，Val，消息等于你好。加
我甚至去打招呼。
好的。
然后我们可以传递信息。现在
如果我们归结为我们的主要功能，我们想要

English: 
wanted to say hello world or hello mate, or
hello John. So how might we do that? Well
that's where a function parameter comes into
play. So to define a function parameter, we'll
go within the parentheses after the function
name, and we'll define this using a notation
of the parameter name colon, the parameter
type. So in this case we're going to say item
two Crete as our parameter name, colon. And
then we want this to be a string value that
we're passing it. Now with dinner function,
we can say, Val, message equals hello. Plus
I even went to greet.
Okay.
And then we could pass in the message. Now
if we come down to our main function, we want

Chinese: 
当人们打招呼时，我们就可以开始了
打字，打招呼。现在我们需要通过
在它向我们建议的参数值中
在这个小工具提示中。所以在这种情况下我们会
凯特琳说。现在，如果我们运行我们的主要功能，
我们现在看到打印出你好的Kotlin
控制台。如果我们想发音
否则，我们可以复制调用和
也许这次我们会在世界上传递它。和
如果我们再次调用我们的主要功能，我们会
现在看到你好凯特琳和你好世界印刷
到控制台。现在，如果我们回去
我们说你好的功能。请注意，有
这条波浪线在这里。这是无关的
功能参数，但这是真的
Caitlyn有趣的特色。凯特琳支持
允许我们替换的字符串模板

English: 
to, when folks say hello, so we can start
typing, say hello. And now we need to pass
in a parameter value which it suggest to us
in this little tool tip. So in this case we'll
say Caitlyn. And now if we run our main function,
we now see hello Kotlin is printed out to
the console. If we wanted to pronounce something
else, we could duplicate the invocation and
maybe this time we'll pass it in world. And
if we invoke our main function again, we'll
now see hello Caitlyn and hello world printed
out to the console. Now if we go back up to
our say hello function. Well notice that there's
this squiggly line here. This is unrelated
to function parameters, but this is a really
interesting feature in Caitlyn. Caitlyn supports
string templates which allow us to substitute

English: 
in variable values or argument values into
a predefined string template. So in this case,
instead of using concatenation, we can say
hello space. And then to define a template,
add value, please a dollar sign and then we
can pass in that parameter name. So now if
we hit run once again, we'll see the same
output as before.
So this is just one more way in which Kotlin
can produce boilerplate for us by allowing
us to define these convenience string templates.
In fact, in this scenario we can take it one
step further and remove the local variable
all together. And then we can actually take
this one step further and define this as a
single expression. Oh shit. Now we have a
say hello function that will take in a parameter
value, which is the item degree. And then

Chinese: 
在变量值或参数值中
预定义的字符串模板。所以在这种情况下，
我们可以说，而不是使用连接
你好空间。然后定义一个模板，
增值，请一个美元符号，然后我们
可以传入该参数名称。所以现在如果
我们再一次跑，我们会看到相同的
像以前一样输出。
所以这只是Kotlin的另一种方式
可以通过允许为我们生产样板
我们定义这些便利字符串模板。
事实上，在这种情况下，我们可以把它拿一个
进一步删除局部变量
全部一起。然后我们可以采取
更进一步，将其定义为
单一表达。妈的。现在我们有一个
说一个会带参数的hello函数
值，即项目度。然后

Chinese: 
它将始终打印出你好项目的程度。
所以现在让我们更新它以获取两个参数
这样我们就可以自定义问候语
无论我们想要达成什么意见。
所以要做到这一点，我们将添加一个新参数
我们会在问候中给这个命名
它是字符串类型。现在我们会
在这里更新我们的字符串模板以包括
那个新参数。
真棒。所以现在我们已经更新了这个功能。
现在我们需要更新它的调用
功能。所以对于第一行，我们可以说，
嘿，常见的，现在我们将为下一个
说你好世界，如果我们现在读得好
看到我们想要的输出。所以加上那个

English: 
it will always print out hello item degree.
So now let's update this to take two parameters
so that we can customize both the greeting
and whatever it is that we want to agree.
So to do that, we're going to add a new parameter
and we will name this one in greeting and
have it be of type string. And now we will
update our string template here to include
that new parameter.
Awesome. So now we've updated the function.
Now we need to update the invocation of that
function. So for this first line we can say,
Hey, common and now for the next one we'll
say hello world and if we read this well now
see our desired output. So by adding that

Chinese: 
第二个参数值，我们现在已经做了我们的
说你好功能更灵活。现在
我们可以添加任意数量的参数
打招呼，但像任何编程语言一样，
如果你的函数中有太多参数，
它可能是你的功能的指标
做得太多了。那是我最后的事情
想指出这方面的功能
时间就是你会注意到这些功能
在任何类型的封闭中都没有定义
类。这些是免费的功能或者它们是
在科特林提到。这些是顶级的
函数如变量，函数都可以
在结束课程或任何课程之外定义
独立于任何相关的类。现在在那里
是关联的函数类型
上课，我们将看看那些
稍后在教程中。
像大多数编程语言一样，Kotlin也有
支持集合数据类型。这些是

English: 
second parameter value, we have now made our
say hello function much more flexible. Now
we can add any number of parameters we want
to say hello, but like any programming language,
if you have too many parameters in your function,
it might be an indicator that your function
is doing too much. Now what last thing I'd
like to point out about functions at this
time is that you'll notice that these functions
are not defined within any type of enclosing
class. These are free functions or as they're
referred to in Kotlin. These are top level
functions like variables, functions can be
defined outside of any in closing class or
independent of any associated class. Now there
are types of functions that are associated
with a class and we'll take a look at those
later on in the tutorial.
Like most programming languages, Kotlin has
support for collection data types. These are

English: 
things like arrays, lists and maps they can
use to group values together and then operate
on them at a later time. So let's start off
by looking at how we can define inner Ray
and Fallon. We'll clear out these invocations
to say hello because we won't need them right
now, but we'll leave the say hello function
definition because we'll come back to it later.
Your create a basic array. We'll create a
new local variable named interesting things
and then we'll use the equal sign and then
we can use a convenience function called array
of in parentheses. This will create an array
of whatever the inferred type is and then
we can start defining values within this function.
So in this case, as soon as I add a string
literal, it can infer that this is going to
be an array of strings. And then we can define

Chinese: 
他们可以像数组，列表和地图这样的东西
用于将值组合在一起然后运行
在他们以后。让我们开始吧
通过观察我们如何定义内部雷
和法伦。我们将清除这些调用
打个招呼，因为我们不需要他们
现在，但我们将留下说你好的功能
定义因为我们稍后会再回过头来。
你创建一个基本数组。我们将创建一个
新的局部变量命名有趣的东西
然后我们将使用等号然后
我们可以使用一个称为数组的便利函数
在括号中。这将创建一个数组
无论推断类型是什么然后
我们可以开始在这个函数中定义值。
所以在这种情况下，只要我添加一个字符串
字面意思，它可以推断出这是怎么回事
是一个字符串数组。然后我们可以定义

English: 
some interesting things like Kotlin programming
or comic books.
Now that we have this variable defined, let's
see what types of operations we can perform
on it. If we start typing interesting things
and hit dot the IDE will start to auto-complete
and show us some of the methods available.
So you see we have a size property, we have
a get method, and we also have this open and
closed of bracket syntax that we can use to
access individual elements in the array. Let's
try printing out some of these values to demonstrate
how we can use the array to start. Let's print
out the size. We can do that by saying print
LN and then we'll do interesting things that
size. Now let's print out the first element

Chinese: 
一些有趣的事情，如Kotlin编程
或漫画书。
现在我们定义了这个变量，让我们来吧
看看我们可以执行哪些类型的操作
在上面。如果我们开始输入有趣的东西
并点击IDE将开始自动完成
并向我们​​展示一些可用的方法。
所以你看我们有一个尺寸属性，我们有
一个get方法，我们也有这个开放和
关闭我们可以使用的括号语法
访问数组中的各个元素。让我们
尝试打印出一些这些值来演示
我们如何使用数组启动。我们打印一下
超出规模。我们可以通过说打印来做到这一点
LN然后我们会做有趣的事情
尺寸。现在让我们打印出第一个元素

Chinese: 
在数组中。我们可以通过打印来做到这一点，
LN，有趣的事情。我们可以使用开放
并且关闭括号然后传入索引。
这就是我们可以方便地进行索引的方式
阵列。
这类似于喷射，所以如果我们复制
那条线，我们可以说得到，再一次，传递
是该数组的零元素。如果我们现在运行
这个，我们会看到三个Caitlyn，Caitlyn，但是
这正如我们所期望的那样。怎么办
如果我们想迭代所有元素
这个数组然后可能打印出来
这些价值观？嗯，还有一些
我们可以用不同的方式做到这一点。目前
我们将看一个基本的for循环，所以我们

English: 
in the array. We can do that by going print,
LN, interesting things. We can use the open
and closed bracket and then pass in an index.
This is how we can conveniently index in fact
array.
This is similar to doing a jet, so if we duplicate
that line, we could say get, and again, passing
is zero element of that array. If we now run
this, we'll see three Caitlyn, Caitlyn, but
this is just as we would expect. Now, what
if we wanted to iterate over all of the elements
of this array and then perhaps print out each
of those values? Well, there are a number
of different ways we could do that. For now
we'll take a look at a basic for-loop so we

Chinese: 
可以开始输入，然后我们可以
在有趣的事情上说有趣的事情。
然后打开和关闭花括号。这是
现在是四个循环的方便语法
科特林。所以这将迭代每个
数组中的值，我们可以访问它们
有趣的东西变量中的值
我们在这四个循环中定义了。
所以现在我们可以打出有趣的东西了
如果我们很好地重新运行这段代码，现在就看看我们
打印出阵列中的每个元素。
所以这种类型的for循环很可能
最类似于你曾经习惯的
来自Java。但是，在Kotlin因为
我们有顶级功能和更高的顺序
功能，真的只是第一类端口
对于全面的功能，我们可以写
代码更有用。那么我们

English: 
could start typing for, and then we could
say interesting thing in interesting things.
Then open and closed curly braces. This is
now the convenient syntax of four loops within
Kotlin. So this is going to iterate over each
value in the array and we can access those
values in the interesting thing variable that
we have defined within this four loop.
So now we can type out interesting thing and
if we rerun this code well now see that we
have printed out each element in the array.
So that type of for-loop is what is probably
most similar to what you're used to if you're
coming from Java. However, in Kotlin because
we have top level functions and higher order
functions, really just first class of port
for functions across the board, we can write
code that is a bit more functional. So let's

English: 
take a look at how we could do a more functional
approach to collection iteration. So or remove
our four loop and now we could say interesting
things doc for each. And what this is is invoking
a for each function that is available in the
standard library. That function then takes
in a another function and returns unit. That
function that we pass it in essentially defines
what to do on each iteration over this collection.
So within our curly braces here, this is where
we can define what we want to do with each
element in contrasting things. Now this might
look a little bit confusing at first, but
don't worry well explain this, but if we simply
want to print out each item in this array,
we can now say print LN and pass in it. It
is the default name for each element in the

Chinese: 
看看我们如何才能发挥更大的功能
收集迭代的方法。所以或删除
我们的四个循环，现在我们可以说有趣
每个人的事情文件。这是什么调用
a。对于每个可用的功能
标准库。然后那个功能
在另一个函数和返回单位。那
我们传递的函数基本上是定义的
在这个集合的每次迭代上做什么。
所以在我们的花括号中，这就是其中之一
我们可以定义我们想要对每个做什么
对比鲜明的元素。现在这可能
起初看起来有点混乱，但是
不要太担心解释这个，但如果我们干脆
想要打印出这个数组中的每个项目，
我们现在可以说打印LN并传入它。它
是每个元素的默认名称

Chinese: 
传递给此Lambda函数的数组
我们在其中定义。所以，如果我们运行这个
好吧，现在看到我们有三个要素
在阵列中打印到控制台。现在
它并不总是非常易读。另一个
如果你想要的话，这里的小快速提示
被命名为别的，你可以重命名
重视传递给Lambda的值。在
这种情况我们可以称之为有趣的事情
然后我们将使用箭头而不是现在
如果我们可以通过调用引用该值
这很有趣，如果我们再一次
运行这个，我们会看到我们有趣的事情
打印到控制台。
你可能正在看这个想知道为什么
我们没有使用开括号和闭括号
在为每个功能调用时。事实上，
我们没有通过可能看起来很奇怪

English: 
array that is passed into this Lambda function
in which we are defining. So if we run this
well, now see that we have our three elements
in the array printed out to the console. Now
it is not always very readable. So another
little quick tip here is if you want it to
be named something else, you can rename that
to value that's passed into the Lambda. In
this case we could call it interesting thing
and then we'll use the arrow and now instead
of if we can reference that value by calling
it interesting thing and once again if we
run this, we'll see that our interesting things
are printed out to the console.
You might be looking at this wondering why
we are not using an open and closed parentheses
when calling the for each function. In fact,
it might seem rather odd that we are not passing

English: 
in that argument two for each, but instead
of have just specify this open and closed
parentheses independent of the rest of the
for each call. So this is actually what's
known as Lambda syntax within Kotlin. Now
we'll look at how to implement this later.
But the idea behind Lambda syntax is that
if you have a function and it's only parameter
is another function, then you can omit the
parentheses all together and you can pass
that function in by specifying this open and
closed parentheses. So again, if we look at
for each, we'll see that it takes a single
function as a parameter so we can omit the
parenthesis values and past that function
into the for each function using the open
and closed curly braces.
And like I said, we'll look at how we actually
define this type of higher order function

Chinese: 
在那个论点中，每个都是两个，而是相反
只是指定这个打开和关闭
圆括号独立于其余部分
每次通话。所以这实际上是什么
在Kotlin中称为Lambda语法。现在
我们稍后会看看如何实现它。
但Lambda语法背后的想法是这样的
如果你有一个功能，它只是一个参数
是另一个功能，那么你可以省略
括号全部在一起，你可以通过
通过指定此打开和
封闭的括号。再说一遍，如果我们看一下
对于每一个，我们会看到它需要一个
作为一个参数，所以我们可以省略
括号值和过去的函数
使用open进入每个函数
并且闭合的花括号。
就像我说的那样，我们会看看我们的实际情况
定义这种类型的高阶函数

English: 
a little bit later in the tutorial. So here
we looked at a basic for each function on
this array collection. But by doing it this
way, we've lost the index data for whatever
index the current interesting thing is in
the containing array. So to handle that there
is another function we can call. So once again
we'll say interesting things and this time
we'll say for each indexed. Now this time
it's going to pass into us the current index
as well as the current string. Now once again,
we'll update this to be named interesting
thing and that one's again, we could print
out these values. So we can say print,L ,N

Chinese: 
稍后在教程中。所以在这里
我们查看了每个函数的基本内容
这个数组集合。但通过这样做
方式，我们丢失了索引数据
索引当前有趣的东西
包含数组。所以要处理那里
是我们可以调用的另一个功能。再一次
我们会说有趣的事情，这一次
我们会说每个索引。现在这一次
它将把当前的指数传递给我们
以及当前的字符串。再一次，
我们将更新此名称有趣
事情和那一个，我们可以打印
出这些价值观。所以我们可以说print，L，N

Chinese: 
我们可以说有趣的是索引。
现在，如果我们打印出来，我们就会看到
我们从数组中获得了值
以及它目前的指数。所以这可能是
如果你需要迭代并且仍然非常有用
维护索引数据。现在一切都那样
我们一直在这里寻找res是适用的
对于列表也是如此。所以，如果我们清除一些
之前的代码，我们现在转到我们的声明
这个有趣的东西变量。现在我们
使用便捷函数数组来
将此变量定义为string类型的数组。
现在还有一个功能列表。
现在，如果我们尝试使用有趣的东西，
我们会看到我们有更多的方法
选择，因为它现在是一个列表而不是
比一个数组。就像阵列一样，我们可以

English: 
and we can say interesting thing is at index.
And now if we print this out, we'll see that
we have gotten the value from the array as
well as its current index. So this could be
really useful if you need to iterate and still
maintain that index data. Now everything that
we've been looking at here for res is applicable
for lists as well. So if we clear out some
of this previous code, we now go to our declaration
of this interesting things variable. Now we're
using the convenience function array of to
define this variable as an array of type string.
Now there's also a list of function as well.
Now if we try to work with interesting things,
we'll see that we have a lot more methods
to choose from because it's now a list rather
than an array. And so like an array, we can

English: 
access individual elements by using a jet
or also by using the bracket syntax like we're
familiar with with arrays as well.
And also like with the array, we have functions
available to us to help with integration.
So if we wanted to print out all of the interesting
things again, once again we can say interesting
things doc for each ad. Once again we'll say
interim vesting thing. We use the arrow here
within our Lambda expression and then we'll
print out the interesting thing and if we
hit run while that we have our three interesting
things printed to the console. Now that we've
looked at arrays and lists, let's take a look
at one more collection type and Kotlin which

Chinese: 
使用喷气机访问单个元素
或者也像我们一样使用括号语法
熟悉数组也是如此。
和阵列一样，我们也有功能
我们可以帮助整合。
所以如果我们想打印出所有有趣的东西
再一次，我们可以说有趣的事情
每个广告的内容文档。我们再一次说
临时归属的事情。我们在这里使用箭头
在我们的Lambda表达式中，然后我们将
打印出有趣的东西，如果我们
命中运行，而我们有三个有趣的
打印到控制台的东西。现在我们已经
看看数组和列表，让我们来看看
还有一种收藏类型和Kotlin

English: 
is map. So let's remove this duration over
our interesting things variable here. Now
let's create a new variable. I'll just name
this map equals and once again there is a
map of function that we can use. Now the map
of function will essentially take in pairs.
Pair is a simple wrapper class containing
two values and that there is also the convenience
function to create pairs.
So if you want to create a basic key value
map we could do so like this. We'll use a
key of one and then we'll use two and then
the value in this case will be a, and then
we'll define it. Another pair, we'll use a
key of two. Then we'll use the two function

Chinese: 
是地图。所以让我们删除这个持续时间
我们有趣的事情在这里变化现在
让我们创建一个新变量。我只是说出来
这张地图等于，再次有一张
我们可以使用的功能图。现在是地图
功能基本上是成对的。
Pair是一个包含的简单包装类
两个值，也有方便
功能来创建对。
所以如果你想创建一个基本的键值
地图我们可以这样做。我们会用一个
一个关键，然后我们将使用两个然后
在这种情况下，值将是a，然后
我们将定义它。另一对，我们将使用一个
两个关键。然后我们将使用这两个函数

English: 
and then a value of B. And then we'll define
one more pair. And we'll say three is our
key to C. so what we've now done is defined
a map with three pairs of values in it. The
keys are one, two and three, and the associated
values are a, B, and C. now we can iterate
over this by saying map for each and it's
going to return to us both the key and the
value. Unfortunately the default to it, not
very useful name. So this case we'll remain
them again within our Lambda expression. So
we'll say key value and then we can print
these out and we'll use a string template
and we'll just say key and then we'll define
an arrow just for some separation and then

Chinese: 
然后是B的值。然后我们将定义
还有一双。我们会说三个是我们的
C的关键所以我们现在所做的就是定义
一张包含三对值的地图。该
键是一，二和三，以及相关的
值是a，B和C.现在我们可以迭代
通过说每个地图和它的地图
要把钥匙和钥匙都归还给我们
值。不幸的是它的默认值，而不是
非常有用的名字。所以这个案子我们会留下来
他们再次在我们的Lambda表达式中。所以
我们会说关键值然后我们可以打印
这些，我们将使用一个字符串模板
我们只是说关键，然后我们将定义
一个箭头只是为了一些分离，然后

Chinese: 
值。现在，如果我们打印出来，那么
现在看到我们给出了每一个关键
和价值对，然后我们可以做
那些我们需要的东西。我们见过
如何定义几种不同的类型
数组和列表等集合
地图。我们也看到了你如何迭代
在这些集合和访问个人
我们收藏的元素。还有
一个有趣的事情要指出的
方式Kotlin处理类似的集合
它区分的方式
可知和纳米类型。凯特琳也有所区别
可变和不可变集合类型之间。
现在这是什么意思？这意味着
默认情况下，Kotlin中的集合类型是不可变的
这样您就无法添加或减去值
该集合一旦最初创建。
那么让我们来看一个例子吧。我们有
使用定义我们有趣的事物列表

English: 
value. And now if we print this out, well
now see that we're giving each of our key
and value pairs and then we could do with
those whatever that we need to. We've seen
how you can define several different types
of collections such as arrays and lists and
maps. And we've also seen how you can iterate
over those collections and access individual
elements from our collection. And there's
an interesting thing to point out about the
way Kotlin handles the collections similar
to the way in which it differentiates between
knowable and nano types. Caitlyn also differentiates
between mutable and immutable collection types.
Now what does this mean? This means that by
default a collection type in Kotlin is immutable
so that you can't add or subtract values from
that collection once it's initially created.
So let's look at an example of this. We have
defined our interesting things list using

English: 
the list of function here. And if we wanted
to try and add something to interesting things,
there's no function available to us to do
that. That's because it's immutable by default.
If we wanted a immutable list, we could use
the mutable list of function. Now if we want
to add something, we can say interesting things.
Dot add and we could add a new string to our
interesting things list. The same goes for
map. If we wanted to add a new key value paired
wire map, you could say map doc put, but there's
no put method available. But if we change
to immutable map, now we could say map dot
put and we can define a new key of four and

Chinese: 
这里的功能列表。如果我们想要的话
尝试添加有趣的东西，
我们没有任何功能可以做
那。那是因为默认情况下它是不可变的。
如果我们想要一个不可变的列表，我们可以使用
可变的功能列表。现在，如果我们想要
添加一些东西，我们可以说有趣的事情。
点添加，我们可以添加一个新的字符串给我们
有趣的事情清单。同样的道理
地图。如果我们想添加一个新的键值配对
电线地图，你可以说地图doc放，但有
没有put方法可用。但如果我们改变
到不可变的地图，现在我们可以说地图点
put，我们可以定义一个新的四键和

English: 
a new value of D. so this is something to
keep in mind. If you have a collection that's
going to be static, once it's defined, then
you're fine to use the regular list of array
of map up, et cetera functions. And that is
a good thing because immutability is often
a desirable trait in your code. However, if
you're going to want to modify the values
in that collection, then you'll have to create
a mutable collection so that you have access
to things like put or add that let you modify
that collection.
Okay,
now that we have an understanding of working
with collections, let's modify RSA hello function
to take a collection parameter so that we
can greet multiple things, will modify first
the name of item to greet two items to greet
because it's now going to be plural because

Chinese: 
D的新值。所以这是要做的事情
记住。如果你有一个集合
一旦它被定义，它将变为静态的
你可以使用常规的数组列表
映射，等等功能。那就是
一件好事，因为不变性往往是
代码中的理想特征。但是，如果
你想要修改这些值
在那个集合中，你必须创建
一个可变的集合，以便您有权访问
像put或add之类的东西让你修改
那个集合。
好的，
现在我们已经了解了工作
使用集合，让我们修改RSA hello函数
采取一个集合参数，以便我们
可以迎接多件事，先修改
要问候两件物品的项目名称
因为它现在将是复数，因为

Chinese: 
它将是一个集合。那会更新
从字符串到字符串列表。然后现在
我们要更新实施
这个功能。所以不是一个单一的
表达式函数，我们将添加一个函数
身体。然后现在我们想要
迭代项目以问候参数。
所以我们会说每个问候点的项目。
然后我们将其粘贴回原版
打印声明。然后我们将继续前进
从这里更新接收器值
项目到克里特岛。它会添加我们的箭头。所以
现在我们有一个你好的打招呼功能
可以将一个集合传递给。然后它会
打印出多行。所以现在我们可以说，
打招呼，我们仍然可以传递我们的习惯

English: 
it will be a collection. And that will update
from string to list of string. And then now
we're going to update the implementation of
this function. So instead of being a single
expression function, we'll add a function
body. And then now we're going to want to
iterate over the items to greet parameter.
So we'll say items to greet dot for each.
And then we'll paste it back in our original
print statement. And then we'll go ahead and
update the receiver value here from it to
item to Crete. It'll add our arrow. And so
now we have a say hello function that you
can pass a collection into. And then it'll
print out multiple lines. So now we can say,
say hello and we can still pass in our custom

Chinese: 
问候所以我们可以打招呼。然后我们可以
把它传递给我们有趣的东西变量。
现在，如果我们点击运行，我们现在看到高Caitlyn，
嗨编程和高漫画书。所以这
只是一个如何传递它的简单示例
在集合类型中作为参数的函数。
包含一个集合没有错
函数中的参数，但功能。
而Kotlin确实提供了额外的一块
能够满足此用途的功能
案例并提供一点额外的灵活性。
现在来说明为什么这可能会很有趣
给我们我们来看一个例子。那么我们
说我们想叫打招呼，我们会通过
或问候，但后来我们不想
在这种情况下传递任何有趣的东西。

English: 
greeting so we can say hi. And then we can
pass it in our interesting things variable.
And now if we click run, we now see high Caitlyn,
hi programming and high comic books. So this
just a quick example of how you can pass it
in a collection type to a function as a parameter.
There's nothing wrong with including a collection
parameter in your function, however functions.
And Kotlin do provide an additional piece
of functionality that can satisfy this use
case and provides a little additional flexibility.
Now to demonstrate why this might be interesting
to us. Let's look at an example. So let's
say we want to call say hello and we'll pass
on or greeting, but then we don't want to
pass in any interesting things in this case.

Chinese: 
好吧，因为这个功能的方式
目前已定义，我们必须通过
第二个论点。所以在这种情况下，如果我们想要的话
传递没有项目，我们将不得不通过
在一个空的列表中，这不是一个很大的
交易，但它也不是最灵活的
处理事物的方式。那我们来看看吧
以及实现此功能的替代方法。
如果我们来这里说我们的问候功能，
我们要修改这第二个。
所以这是一个VAR拱外围VAR ARG
Kotlin中的关键字。它基本上代表了
可变数量的参数。所以在这
case，而不是取一个字符串列表，
我们将定义一个VAR R的字符串。这说明
我们要采用变量的编译器

English: 
Well, because of the way that this function
is currently defined, we have to pass in the
second argument. So in this case, if we wanted
to pass in no items, we would have to pass
in an empty list, which isn't really a big
deal, but it's also not the most flexible
way of handling things. So let's take a look
and alternative means of achieving this functionality.
If we come up here to our say hello function,
we're going to modify this second.
So that is a VAR arch perimeter VAR ARG is
a keyword in Kotlin. It essentially represents
a variable number of arguments. So in this
case, instead of taking a list of string,
we'll define a VAR R of string. This tells
the compiler that we're going to take a variable

Chinese: 
初始化后的字符串参数数
问候这个功能的论点。所以现在
如果我们试图传递一些东西打个招呼，
我们的悲痛，现在我们是第一次通过
实际上不必在之后传递任何东西
最初的论点。这是因为
[听不清]参数基本上是
被视为一个无论哪种类型的数组
用于指定。所以在这种情况下，项目来
GRI现在是一个类型字符串数组。因此，如果
问候后我们不传递任何物品，
它将被视为一个空数组。要是我们
确实想要开始传递物品，我们可以做到
用逗号分隔它们。所以
可以说Kotlin，现在这将是一个
一号大小的数组。但真正的灵活性在哪里

English: 
number of string arguments after the initial
greeting argument to this function. So now
if we try to pass something in to say hello,
well first pass in our grieving and now we
don't actually have to pass anything in after
the initial argument. This is because the
[inaudible] parameter will essentially be
treated as an array of whichever type it's
used to specify. So in this case, items to
GRI is now an array of type string. So if
we don't pass any items after the greeting,
it will be treated as an empty array. If we
did want to start to pass items, we can do
that by separating them with commas. So it
could say Kotlin and now this would be an
array of size one. But where the real flexibility

Chinese: 
我们现在可以开始定义许多论点了
价值观。
现在所有这些论点都是如此
传入将被组合在一起，进行处理
作为一个数组。在我们的函数实现中，
我们仍然可以遍历所有元素
在那个数组中。所以如果我们现在运行它，我们应该
得到与以前相同的装备。所以通过使用
我们的VAR arc参数，我们已经淘汰了
需要始终在初始后传入一个值
问候论点，让我们有更大的
灵活性，因为它将支持零
或任何其他数量的参数值
通过它。现在它非常方便
能够将多个参数传递给它
[听不清]硬边界。但是，你是

English: 
comes is we can now start to define many argument
values here.
And so now all of those arguments that are
passed in will be grouped together, treated
as an array. And so in our function implementation,
we can still iterate over all the elements
in that array. So if we now run this, we should
get the same outfit as before. So by using
our VAR arc parameter, we've eliminated the
need to always pass in a value after the initial
greeting argument and lets us have greater
flexibility because it will support zero one
or any other number of argument values to
be passed it. Now it's very convenient to
be able to pass multiple arguments to this
[inaudible] hard perimeter. However, you're

Chinese: 
通常不会硬编码那些
在编译时手动参数。
更有可能你会获得一系列的
来自网络请求或数据库的值
然后你会想要传递那些
因此你可能会认为它会如此
在初始化之后传入数组很简单
问候。所以让我们试试吧。我们可以改变
两个数组的列表，然后在我之后，
我们会传递有趣的东西。哦，不幸的是
这不起作用。如果你看看
空气，看到一个需要找到的字符串数组
的字符串。那么你如何实际传入
到目前为止ARG的一系列现有值
周长？嗯，你可以用
传播运营商和所有传播运营商
是，在数组之前应用星号

English: 
usually not going to be hard coding those
arguments in manually during compiled time.
More likely you're going to get a array of
values from a network request or a database
and then you're going to want to pass it those
in. So you might think that it would be as
simple as passing in an array after that initial
greeting. So let's try that. We could change
list of two array of, and then after I,
we'll pass in interesting things. Oh, unfortunately
this does not work. And if you look at the
air, the see a requires string found array
of string. So how do you actually pass in
an array of existing values to this far ARG
perimeter? Well, you can do that with the
spread operator and all the spread operator
is, is applying the asterisk before the array

English: 
variable when you pass it in as an argument
value. So now if we hit run, we'll see that
the compiler is now accepting that array and
we are iterating over each item in that interesting
things array. So this is how you can pass
in an existing collection as a VAR ARD parameter.
Another really interesting and powerful feature
with Kotlin functions are named arguments.
Now let's take a look at an example of what
name arguments provide to us. Let's start
by cleaning out our main function and then
we're going to define a new simple function
that will take a greeting and a name and then
print that up.
So now when we want to call this new Greek
person function secret person, hi, and then
I'll use my name here. Now this is fine and
it's very easy to understand because the ID

Chinese: 
将参数作为参数传递时的变量
值。所以现在，如果我们点击，我们会看到
编译器现在接受该数组和
我们正在迭代那个有趣的项目
东西阵列。所以这就是你可以通过的方式
在现有集合中作为VAR ARD参数。
另一个非常有趣和强大的功能
用Kotlin函数命名参数。
现在让我们来看看一个例子
name参数提供给我们。开始吧
通过清理我们的主要功能然后
我们将定义一个新的简单函数
那将是一个问候和一个名字然后
打印出来。
所以现在我们想要称这个新的希腊语
人功能秘密人，嗨，然后
我会在这里使用我的名字。现在这很好
它很容易理解，因为ID

English: 
is helping us and showing, okay, this is the
greeting argument. This is the name argument.
However, if you are in a code review, you
might not be able to know exactly which order
these arguments are supposed to be passed
in. Also, if you wanted to modify the function
signature of Greek person down the line, you'd
have to make sure that these are in the same
order because since they share the same type,
you could mix that order up without getting
any type of compiler pair. Now what made arguments
allow us to do is specify which parameter
this argument value is going to be used for.
So what does that actually look like in practice?
Well, it looks like defining the name of the
parameter and then an equal sign. And then
here we can say main equals. And so now we're
saying very explicitly assigned, high to greeting

Chinese: 
正在帮助我们并展示，好吧，这就是了
问候论点。这是名称参数。
但是，如果您正在进行代码审查，那么您
可能无法准确知道哪个订单
这些论点应该被传递
in。另外，如果你想修改这个功能
希腊人签名，你
必须确保这些是相同的
订单，因为他们共享相同的类型，
你可以混合那个订单而不会得到
任何类型的编译器对。现在是什么造成了争论
允许我们做的是指定哪个参数
这个参数值将被用于。
那么在实践中实际上是什么样的呢？
好吧，它看起来像定义的名称
参数然后是等号。然后
在这里我们可以说主要等于。所以现在我们是
说得非常明确，高度问候

Chinese: 
和Nate。对我来说，这很酷
允许我们这样做实际上是混淆了订单
这些论点。所以现在我们可以
首先传递第二个参数和第一个参数
参数秒，以便我们可以实际
从理论上修改希腊语的签名
人改变这些参数的顺序
它不会影响到的调用
那个功能。凯特琳允许我们接受这个
通过杠杆作用进一步提高灵活性
默认参数值。再一次，让我们来吧
看看我们希腊人的例子。所以在这里
我们现在能够通过任何方式传递参数
我们想要的订单。如果我们使用名称参数
在税收，但如果我们想通过主要
首先，然后甚至没有通过问候？

English: 
and Nate. To me, the cool thing that this
allows us to do is actually mix up the order
of these arguments. So now we can actually
pass the second parameter first and the first
parameter second so that we could actually
theoretically modify the signature of Greek
person changing the order of these parameters
and it wouldn't impact the invocations of
that function. Caitlyn allows us to take this
flexibility one step further by leveraging
default parameter values. So once again, let's
look at our Greek person example. So here
we are now able to pass the arguments in whatever
order we want. If we're using name arguments
in tax, but what if we wanted to pass main
first and then not even passing the greeting?

English: 
Well now we get an error because it says no
value past for perimeter greeting. So as great
persons currently defined, it must take both
arguments, even if they are in a mixed up
order. Default parameter values allow us to
change that. It allows us to tell the compiler
what the default value should be if not as
specified. So for greeting, we could provide
a default value of hello and for name we'd
get provided default value of Kotlin. You'll
see now great person can be called by only
specifying a single argument value. And if
we run this, we'll see. It's going to say
hello mate. So it's giving the default greeting
value and then it was using the value for
the name that we passed in now because both

Chinese: 
那么现在我们得到一个错误，因为它说不
价值过去为周边问候。太棒了
目前定义的人，必须两者兼顾
争论，即使他们混在一起
订购。默认参数值允许我们
改变这一点。它允许我们告诉编译器
默认值应该是什么，如果不是
指定。所以对于问候，我们可以提供
hello的默认值和我们的名字
获得Kotlin的默认值。你会
看到现在伟大的人只能被召唤
指定单个参数值。而如果
我们运行这个，我们会看到。它会说
你好伙伴。所以它给出了默认问候语
值然后它使用的值为
我们现在传递的名字，因为两者

English: 
arguments have defaults, we could actually
call this without passing any arguments in.
And if we run it now, we'll see it's using
both defaults and prints out.
Hello Kotlin. Now this becomes a really powerful
feature because now we can not only mix up
the order in which we pass arguments, but
we don't even have to pass all of them in.
This actually allows us to replicate functionality
of the builder pattern without actually having
to write getters and setters and have private
constructors and all of that. We can configure
and reuse functions and objects by leveraging
these default values and the named arguments,
syntax, Wilde, Decaux parameter values, main
argument and VAR. Our parameters are really
convenient and flexible and powerful. They
do have limitations as well. So I want to

Chinese: 
参数有默认值，我们实际上可以
在不传递任何参数的情况下调用它。
如果我们现在运行它，我们会看到它正在使用
默认并打印输出。
你好Kotlin。现在这变得非常强大
功能，因为现在我们不仅可以混淆
我们传递参数的顺序，但是
我们甚至不必通过所有这些。
这实际上允许我们复制功能
of the builder pattern without actually having
to write getters and setters and have private
constructors and all of that.我们可以配置
and reuse functions and objects by leveraging
these default values and the named arguments,
syntax, Wilde, Decaux parameter values, main
argument and VAR.我们的参数确实如此
方便灵活，功能强大。他们
do have limitations as well.所以我想

English: 
illustrate one of those limitations. So we're
going to go back to our say hello function.
Let's redefine our interesting things are
right. And so now if I want to invoke, say
hello and I want to pass things in order with
the greeting and then the interesting things
I can do that no problem. And if I run this,
we'll get our three lines of output.
And so now what if we wanted to use named
arguments in techs? Well we could do that
as well. Breathing equals high. However, as
soon as I add the name argument syntax to
the first parameter, I get this air saying
mixing name and position arguments is not
allowed. So this is one of those limitations.
As soon as you use named arguments in tax
for what argument, everything that follows,
that must also be named. So in this case,

Chinese: 
说明了其中一个限制。 So we're
going to go back to our say hello function.
Let's redefine our interesting things are
right.现在，如果我想调用，请说
hello and I want to pass things in order with
the greeting and then the interesting things
我能做到这一点没问题。 And if I run this,
we'll get our three lines of output.
And so now what if we wanted to use named
arguments in techs?好吧，我们可以做到
同样。呼吸等于高。 However, as
soon as I add the name argument syntax to
the first parameter, I get this air saying
mixing name and position arguments is not
允许。所以这是其中一个限制。
只要在税收中使用命名参数
for what argument, everything that follows,
that must also be named.所以在这种情况下，

Chinese: 
I could fix this by saying items to treat
equals and now I can run this again and I'll
get the desired three lines of output once
再次。现在我可以将它们混合起来
and because both of them are using names,
argument syntax, there are no problems here.
And once again, we could run this and we would
get our desired output.
Now we're going to take a look at how we can
create a simple class in Kotlin.现在直到
this point, we've been working within a single
main dot KT file.但是，现在我们是
going to move into classes, let's go ahead
and add a new file.所以我们会过来的
our project panel, right click source, go
to new Kotlin file or class, and we're going

English: 
I could fix this by saying items to treat
equals and now I can run this again and I'll
get the desired three lines of output once
again. Now I could mix these up though
and because both of them are using names,
argument syntax, there are no problems here.
And once again, we could run this and we would
get our desired output.
Now we're going to take a look at how we can
create a simple class in Kotlin. Now up until
this point, we've been working within a single
main dot K T file. However, now that we're
going to move into classes, let's go ahead
and add a new file. So we'll come over to
our project panel, right click source, go
to new Kotlin file or class, and we're going

Chinese: 
to come down and on this dropdown we're going
to select class and then we're going to name
这个班的人然后点击进入。我们可以
see here, then it automatically has created
a person class for us and I might notice that
this class is quite simple.让我们来吧
看看这个班级实际上是如何运作的。至
start, we have the class keyword followed
通过班级名称然后真的就是这样。
我们甚至可以选择删除这些
大括号。 Since we're not defining any
properties or methods at this time, if we
wanted to then use this class, we could return
to our main function here.然后我们可以
像这样创建一个类的实例。
所以我们将创建一个名为person equals的变量

English: 
to come down and on this dropdown we're going
to select class and then we're going to name
this class person and then hit enter. We can
see here, then it automatically has created
a person class for us and I might notice that
this class is quite simple. So let's take
a look at how this class actually works. To
start, we have the class keyword followed
by the class name and then really that's it.
We could actually even optionally remove these
curly braces. Since we're not defining any
properties or methods at this time, if we
wanted to then use this class, we could return
to our main function here. And then we can
create an instance of the class like this.
So we'll create a variable named person equals

English: 
person. Now this syntax right here is how
you create a new instance of a class. Notice
there's no new keyword and Caitlyn, you do
not have to explicitly call new. You can simply
specify the class name and then the constructor
and any arguments that you need to pass into.
It can may notice
that we were able to create an instance of
the person class using this empty constructor.
However, if we go back to our class definition,
we don't have any constructor defined. This
is because when you're defining a class in
Claplan, if you do not have any properties
defined in your primary constructor or any
arguments defined in your primary constructor,
then you can actually just omit that primary
constructor altogether. So what we see here,

Chinese: 
人。 Now this syntax right here is how
you create a new instance of a class.注意
there's no new keyword and Caitlyn, you do
not have to explicitly call new.你可以简单
specify the class name and then the constructor
and any arguments that you need to pass into.
它可能会注意到
that we were able to create an instance of
the person class using this empty constructor.
However, if we go back to our class definition,
we don't have any constructor defined.这个
is because when you're defining a class in
Claplan, if you do not have any properties
defined in your primary constructor or any
arguments defined in your primary constructor,
then you can actually just omit that primary
constructor altogether.那么我们在这里看到的，

English: 
class person is really a shorthand form of
this. If we wanted to explicitly define this
primary constructor, we can do so by adding
the constructor keyword and then the opening
closed parentheses. You'll see here that it
actually gives us a message recommending that
we remove the empty primary constructor. Now
we could also modify this primary constructor
by just removing the constructor keyword and
moving the open and closed parentheses directly
after the classmate. However, we still get
that same recommendation to remove the empty
primary constructor. So let's add a primary
constructor once again. And this time let's
actually define a parameter that must be passed
into this constructor. So if we're creating
a person in class, let's pass in a first and
last name for this person. So we could say

Chinese: 
class person is really a shorthand form of
这个。如果我们想明确定义它
primary constructor, we can do so by adding
the constructor keyword and then the opening
封闭的括号。 You'll see here that it
actually gives us a message recommending that
我们删除空的主构造函数。现在
we could also modify this primary constructor
by just removing the constructor keyword and
moving the open and closed parentheses directly
在同学之后。 However, we still get
that same recommendation to remove the empty
主要构造函数。 So let's add a primary
constructor once again.这次让我们来吧
actually define a parameter that must be passed
into this constructor.所以，如果我们正在创造
a person in class, let's pass in a first and
last name for this person.所以我们可以说

English: 
first name string, last name string.
So now we have two unused parameters that
we pass it into the constructor. And now if
we come back here to the creation of an instance
of our person class, we'll see that we now
have a compiler error saying no value pass
for our printers. So I'll go ahead and I'll
pass it in my first and last name here so
we can come back here and we're not actually
doing anything yet with these perimeters.
So let's change that. Let's define our first
property on our person class. So since we're
passing in first name and last name, let's
define properties for first name and last
name. So we can say Val, first name street,

Chinese: 
名字字符串，姓氏字符串。
So now we have two unused parameters that
we pass it into the constructor.现在如果
we come back here to the creation of an instance
of our person class, we'll see that we now
have a compiler error saying no value pass
for our printers.所以我会继续前进，我会
pass it in my first and last name here so
we can come back here and we're not actually
用这些周边做任何事情。
所以让我们改变这一点。让我们来定义我们的第一个
属于我们班级的财产。 So since we're
passing in first name and last name, let's
define properties for first name and last
名称。所以我们可以说Val，名字街道，

English: 
thou last name street. Now you notice that
both of these, now I have red areas underneath
them saying property must be initialized or
be abstract. And there's a couple of different
ways that we can initialize these.
The first way we'll look at is using and then
hit block can define it in a net block by
using the unit keyword and then open and close
curly braces. And a net block is a piece of
code that is run anytime. An instance of this
class is run and you can actually have multiple
admit blocks that will be processed in the
order in which they are defined within your
class body. So within this a net block we
can initialize our property values using the
parameters from our primary constructor. So
we'll say first name equals underscore, first
name, last name equals underscore, last name.
Now we have initialized properties. But if

Chinese: 
你的姓氏街。 Now you notice that
both of these, now I have red areas underneath
them saying property must be initialized or
be abstract.还有一些不同的东西
我们可以初始化这些方法。
The first way we'll look at is using and then
hit block can define it in a net block by
using the unit keyword and then open and close
大括号。并且网块是一块
随时运行的代码。 An instance of this
class is run and you can actually have multiple
admit blocks that will be processed in the
order in which they are defined within your
阶级身体。 So within this a net block we
can initialize our property values using the
我们的主要构造函数中的参数。所以
we'll say first name equals underscore, first
姓名，姓氏等于下划线，姓氏。
现在我们已经初始化了属性。但如果

English: 
we look up at where those properties are declared,
we will see these little warnings saying,
can be joined with assignment. What does that
mean? Well this is the other way in which
we could initialize these values.
We could actually get rid of the NIC block
here and we could initialize these at the
point where they're declared by saying equals
underscore first name equals underscore last
name. So now we're passing in those parameters
to the constructor and then immediately declaring
and initializing properties on the class.
So now if we go back to our usage of this
person class, after we create the instance
of person, we can now access those properties.
Jax as the properties where you type person.
Dot and then we can access the properties

Chinese: 
we look up at where those properties are declared,
we will see these little warnings saying,
可以与任务一起加入。 What does that
mean?那么这是另一种方式
我们可以初始化这些值。
We could actually get rid of the NIC block
here and we could initialize these at the
point where they're declared by saying equals
underscore first name equals underscore last
名称。 So now we're passing in those parameters
to the constructor and then immediately declaring
并初始化类的属性。
所以现在我们回到我们的用法
person class, after we create the instance
of person, we can now access those properties.
Jax作为您键入人物的属性。
点然后我们就可以访问这些属性了

English: 
by their names directly. So we can say last
name or person dot first name. Now you noticed
that we're not using a getter here in Kotlin.
This is known as property access syntax. You
can reference properties directly by their
name without having to worry about the getter
or the setter. So now if we go back over track
class, we could actually simplify this even
a little bit more. And to do that we'll go
ahead and remove these properties.
And so now instead of passing in a parameter
to the constructor and then defining a separate
property that mirrors that parameter, we can
actually declare the property directly and
the primary constructor. So to do that, we'll
come up here, we'll remove this underscore
since this is now going to be the property
name and then we'll add the vow keyword. And

Chinese: 
由他们的名字直接。 So we can say last
name or person dot first name.现在你注意到了
我们在Kotlin没有使用吸气剂。
这称为属性访问语法。您
can reference properties directly by their
name without having to worry about the getter
或者是二传手。 So now if we go back over track
class, we could actually simplify this even
多一点点。 And to do that we'll go
ahead and remove these properties.
And so now instead of passing in a parameter
to the constructor and then defining a separate
property that mirrors that parameter, we can
actually declare the property directly and
主要构造函数。 So to do that, we'll
come up here, we'll remove this underscore
since this is now going to be the property
name and then we'll add the vow keyword.和

English: 
now when we have defined a first name and
last name properties within our primary constructor
directly, and if we go back to our usage,
we see that nothing has changed here. We can
still initialize the class in the same way
and still access our last name and first properties
the same way. So far we've been working with
the primary constructor within our class declaration,
but it's also possible to define what are
known as secondary constructors. Secondary
constructors can provide alternative means
for you to instantiate an instance of your
class.
So let's work with an example. Let's say we
want to create a secondary constructor that
takes no parameters so that we don't have
to always pass values in what we want to create
a new person object. So to create a secondary
constructor, we'll use the constructor keyword
and then open and close parentheses. And in
this example we're not going to pass in any

Chinese: 
now when we have defined a first name and
last name properties within our primary constructor
directly, and if we go back to our usage,
we see that nothing has changed here.我们可以
still initialize the class in the same way
and still access our last name and first properties
一样的方法。 So far we've been working with
the primary constructor within our class declaration,
but it's also possible to define what are
known as secondary constructors.次要
constructors can provide alternative means
for you to instantiate an instance of your
类。
让我们来举个例子吧。 Let's say we
want to create a secondary constructor that
takes no parameters so that we don't have
to always pass values in what we want to create
一个新的人物。 So to create a secondary
constructor, we'll use the constructor keyword
然后打开和关闭括号。 And in
this example we're not going to pass in any

English: 
parameters. We didn't need to call through
to the primary constructor. To do that we
use colon and then the this keyword open and
closed parentheses. And then now we need to
satisfy any parameters that are declared in
the primary constructor. So in this case,
let's define some default first and last name
values. So for our first name we'll use Peter
and last name. We'll use Parker.
Okay.
And then we can define a body for the secondary
constructor. And to just take a look at how
this works with the NetBox. Let's go ahead
and add a print statement here that says secondary
constructor
[inaudible].

Chinese: 
参数。 We didn't need to call through
to the primary constructor.要做到这一点，我们
use colon and then the this keyword open and
封闭的括号。然后现在我们需要
satisfy any parameters that are declared in
主要构造函数。所以在这种情况下，
let's define some default first and last name
values.因此，对于我们的名字，我们将使用彼得
和姓氏。我们将使用派克。
好的。
And then we can define a body for the secondary
构造函数。而且只是看看如何
这适用于NetBox。 Let's go ahead
and add a print statement here that says secondary
构造函数
[听不见的。

Chinese: 
Well then add and then that block, and we'll
put a message here that says, and that one.
And then just for fun, let's add a second,
a net block after the secondary constructor
我们也会在里面打印出来。 Now let's run
our main function and just see what happens.
[听不见]
so in this case we're using the primary constructor
so we can specify and explicit values for
名字和姓氏。 So we'll see that
the secondary constructor is never called,
but both admit box are called and log out
to the console.所以现在让我们删除显式
arguments that are being passed in. And now
let's rerun this
[听不见]
and now this time we'll see that I didn't
block one is run and Nickboch two is run and
然后我们的二级构造函数运行
[听不见的。

English: 
Well then add and then that block, and we'll
put a message here that says, and that one.
And then just for fun, let's add a second,
a net block after the secondary constructor
and we'll print out in it too. Now let's run
our main function and just see what happens.
[inaudible]
so in this case we're using the primary constructor
so we can specify and explicit values for
the first and last name. So we'll see that
the secondary constructor is never called,
but both admit box are called and log out
to the console. So now let's remove the explicit
arguments that are being passed in. And now
let's rerun this
[inaudible]
and now this time we'll see that I didn't
block one is run and Nickboch two is run and
then our secondary constructor was run
[inaudible].

English: 
So what this shows is that the admit blocks
are always going to run before the secondary
constructor. Now the Invitbox will execute
in order in which they're defined within the
class body and the secondary constructor will
be called. Now in this example, and actually
in many practical examples when using Kotlin
on real projects, a secondary constructor
isn't strictly necessary because of the power
of default parameter values. So in this case
we can remove all of this within our class
body and instead we can define default values
here in the primary constructor.
Okay.
Now if we go back over to our usage, we can
still use the person class as if it had this
empty primary constructor because both parameters
have default values.

Chinese: 
So what this shows is that the admit blocks
are always going to run before the secondary
构造函数。 Now the Invitbox will execute
in order in which they're defined within the
class body and the secondary constructor will
be called.现在在这个例子中，实际上
in many practical examples when using Kotlin
on real projects, a secondary constructor
isn't strictly necessary because of the power
of default parameter values.所以在这种情况下
we can remove all of this within our class
body and instead we can define default values
这里是主构造函数。
好的。
Now if we go back over to our usage, we can
still use the person class as if it had this
empty primary constructor because both parameters
have default values.

Chinese: 
Now let's look a bit more closely at class
属性。现在我们已经定义了两个
我们的主要构造函数中的属性。
这两个都是只读属性
they have no center, but they do have a getter
可用。那个Gitter就是我们的能力
to leverage property access and tax and reference
those properties directly as we are doing
这里是我们的主要功能。 Let's explore this
more fully by adding another property.让我们
添加昵称属性。在这种情况下，我们会
use VAR because it's not going to be set initially.
We'll call it nickname string and we're going
to go ahead and make this a notable string
and then we'll go ahead and set that initially
to know.现在让我们来看看我们是否打字。

English: 
Now let's look a bit more closely at class
properties. Now we've already defined two
properties within our primary constructor.
Both of these are read only properties so
they have no center, but they do have a getter
available. That Gitter is how we are able
to leverage property access and tax and reference
those properties directly as we are doing
here in our main function. Let's explore this
more fully by adding another property. Let's
add a nickname property. In this case we'll
use VAR because it's not going to be set initially.
We'll call it nickname string and we're going
to go ahead and make this a notable string
and then we'll go ahead and set that initially
to know. Now let's see if we type person.

Chinese: 
点。 We see that we have a nickname property,
but unlike last name and first name, this
是一个可变的财产。
所以我们实际上可以为此赋值。
所以我们可以说等于。然后是我的昵称
成长是阴影。 So assign that string
to this nickname property.所以，如果我们回去
to our person class, let's look at this property
a bit more closely.我们已经提到了
that properties and Caitlyn will get getters
and setters generated for them automatically
由编译器。 So if your property is a
vow, it will have a get or generated.如果它是
a bar, it will have it getter and a setter
产生。但是，如果你不想依赖，那该怎么办？
on the default behavior of these getters and
senators?也许你想做一些复杂的事情
内在的逻辑。 Or maybe you want to log
something out for debugging purposes.好，
you can override the behavior of these default
getters and setters and provide your own implementations.

English: 
Dot. We see that we have a nickname property,
but unlike last name and first name, this
is a mutable property.
So we can actually assign a value to this.
So we can say equals. And then my nickname
growing up was shades. So assign that string
to this nickname property. So if we go back
to our person class, let's look at this property
a bit more closely. We've already mentioned
that properties and Caitlyn will get getters
and setters generated for them automatically
by the compiler. So if your property is a
vow, it will have a get or generated. If it's
a bar, it will have it getter and a setter
generated. But what if you don't want to rely
on the default behavior of these getters and
senators? Maybe you want to do some complex
logic within that. Or maybe you want to log
something out for debugging purposes. Well,
you can override the behavior of these default
getters and setters and provide your own implementations.

Chinese: 
So let's log out every time a new nickname
is set.
要做到这一点。 We go to our nipping declaration
and then we'll go to the next line and then
我们将空间超过四次。 And now if we
start typing set, we'll see auto-completion
这里提出了几个选项。 So I'm
going to choose this bottom one.那是什么呢
essentially does is allows us to define the
function behavior for wins set is called.
Now when we do this, this will generate a
backing field for this property.所以实际上
assign the new value to our nickname property,
we need to use a special keyword called field
等于价值。 If we didn't make this call,
then the value of nickname would never actually
得到更新。 And now we are free to implement
whatever you want.所以在这种情况下我们可以

English: 
So let's log out every time a new nickname
is set.
To do that. We go to our nipping declaration
and then we'll go to the next line and then
we'll space over four times. And now if we
start typing set, we'll see auto-completion
comes up with several options here. So I'm
going to choose this bottom one. So what this
essentially does is allows us to define the
function behavior for wins set is called.
Now when we do this, this will generate a
backing field for this property. So to actually
assign the new value to our nickname property,
we need to use a special keyword called field
equals value. If we didn't make this call,
then the value of nickname would never actually
be updated. And now we are free to implement
whatever you want. So in this case we can

English: 
update this with a log message that says the
new make name is dollar value. So now if we
go back over to our main, let's see what this
looks like. So we're assigning one nickname,
person that nickname that. Let's assign a
nother nickname. In this case we'll just say
new nickname. Now if we run this, we can take
a look at the log. So you see here each time
for assigning a value to the nickname property,
our log statement is being run. Similarly,
we can override the default Gether. We do
this very much the same way. I'll start by
saying get,
there's no new value to set so there's no
value being passed in. So instead we'll just

Chinese: 
update this with a log message that says the
new make name is dollar value.所以现在，如果我们
go back over to our main, let's see what this
looks like.所以我们分配了一个昵称，
那个绰号的人。 Let's assign a
nother nickname.在这种情况下，我们只会说
新昵称。 Now if we run this, we can take
a look at the log.所以你每次都看到这里
for assigning a value to the nickname property,
our log statement is being run.同样的，
我们可以覆盖默认的Gether。 We do
this very much the same way.我会先说
说得到，
there's no new value to set so there's no
value being passed in. So instead we'll just

Chinese: 
锁定这个。说打印线。 The return
value is dollar field.我们还有那个
field backing value, which is what his storing
the actual value of nickname.然后我们就是
要返回字段的值。所以现在
we'll come back over to our main, we'll use
a print statement here, person dot nickname
and if we run this, we're seeing that our
中心被多次召唤。然后
our getter is being called and the value logged
出。 And then finally our print statement
here in the main function.现在我们已经
explored class properties, let's take a look
at how we can add a method to our person class.

English: 
lock this out. Say print line. The return
value is dollar field. We still have that
field backing value, which is what his storing
the actual value of nickname. And then we're
going to return the value of field. So now
we'll come back over to our main, we'll use
a print statement here, person dot nickname
and if we run this, we're seeing that our
center is being called multiple times. Then
our getter is being called and the value logged
out. And then finally our print statement
here in the main function. Now that we've
explored class properties, let's take a look
at how we can add a method to our person class.

English: 
To add a method, we really just need to define
it function within our class declaration.
That's great. A method called print info.
It'll take no parameters
and it's just going to print out the user's
info. So in this case we'll use a print statement
and then we'll use a string template to pronounce
the first name, the nickname, and the last
name. So we go back over here to our main
class. Let's go ahead and remove most of this.
Now if we want to call the method on our person
variable, we can type person dot and then
print info. So now if we run this, we see
Peter, no Parker. So our method worked, however,
the formatting is maybe not quite what we
would have wanted because nickname was no

Chinese: 
To add a method, we really just need to define
it function within our class declaration.
那很棒。一种称为打印信息的方法。
它不需要任何参数
and it's just going to print out the user's
信息。所以在这种情况下我们将使用print语句
and then we'll use a string template to pronounce
the first name, the nickname, and the last
名称。 So we go back over here to our main
类。让我们继续并删除大部分内容。
Now if we want to call the method on our person
variable, we can type person dot and then
打印信息。 So now if we run this, we see
Peter, no Parker.所以我们的方法有效，
the formatting is maybe not quite what we
would have wanted because nickname was no

Chinese: 
like print info was called, we printed out
the word no rather than anything possibly
更有用。 So let's refactor this method
a little bit and see if we can improve that.
这太好了。 A variable called nickname
to print.然后让我们检查是否
不是这不是。 So we can say if nickname
does not equal no, we'll go ahead and use
绰号别的。 We'll use this more descriptive
string of no nickname and now we can update
this implementation and instead of using nickname
directly, we'll use this new local variable.
So now if we go over to our main again and
we run this, now we see our output is formatted

English: 
like print info was called, we printed out
the word no rather than anything possibly
more useful. So let's refactor this method
a little bit and see if we can improve that.
So that's great. A variable called nickname
to print. And then let's check whether or
not this is no. So we can say if nickname
does not equal no, we'll go ahead and use
the nickname else. We'll use this more descriptive
string of no nickname and now we can update
this implementation and instead of using nickname
directly, we'll use this new local variable.
So now if we go over to our main again and
we run this, now we see our output is formatted

Chinese: 
a little bit better now while the output now
looks better, this expression right here is
有点冗长。 This type of check where
we're comparing whether or not something is
no and then providing one of two values comes
up quite a bit and Kotlin and because of that
there's actually a convenient syntax we can
use that simplifies this expression.所以呢
we can do is this like maybe question Mark
Colon, no nickname.
The question Mark Colon is what's known as
the Elvis operator and Caitlyn, what this
expression is saying is check what's on the
left side of the Elvis operator.如果那边
of the expression is not no, then go ahead
and return that.否则返回是什么
永远在表达的右边。
所以，如果我们回到缅因州并运行一次

English: 
a little bit better now while the output now
looks better, this expression right here is
a little bit verbose. This type of check where
we're comparing whether or not something is
no and then providing one of two values comes
up quite a bit and Kotlin and because of that
there's actually a convenient syntax we can
use that simplifies this expression. So what
we can do is this like maybe question Mark
Colon, no nickname.
The question Mark Colon is what's known as
the Elvis operator and Caitlyn, what this
expression is saying is check what's on the
left side of the Elvis operator. If that side
of the expression is not no, then go ahead
and return that. Otherwise return what is
ever on the right hand side of the expression.
So if we go back to Maine and run this once

Chinese: 
again, well now see that we're still getting
our updated output.所以这个案例，猫王
operator is just a much more concise way of
doing that.如果是其他检查。现在我想接受
a minute and talk about visibility modifiers
within Kotlin.在这里查看此代码，
you'll see nowhere do we have any type of
visibility modifier specified.但是，如果
we go over here to our main, we're able to
create a new instance of this class.我们是
able to call the print info method and we
are able to access all of the properties.
This is because in Kotlin classes, properties,
methods, really visibility in general is public
默认情况下。 If we wanted to modify the visibility
of any of these, we can add one of for visibility

English: 
again, well now see that we're still getting
our updated output. So this case, the Elvis
operator is just a much more concise way of
doing that. If else check. Now I want to take
a minute and talk about visibility modifiers
within Kotlin. Looking at this code here,
you'll see nowhere do we have any type of
visibility modifier specified. However, if
we go over here to our main, we're able to
create a new instance of this class. We are
able to call the print info method and we
are able to access all of the properties.
This is because in Kotlin classes, properties,
methods, really visibility in general is public
by default. If we wanted to modify the visibility
of any of these, we can add one of for visibility

English: 
modifiers. So from the class we could add
public here. However, because it's public
by default, this is not needed. We could add
internal. Internal means that this class is
public within the module. So in our case,
because we're in a single module, this doesn't
change anything. We can also make this private.
Once we make it private, we'll now see that
it's no longer available in our main dotK
T file and this case a private class is only
available within the file in which it's implemented.
Now we get to apply similar rules to our nickname
property. If we make this an internal property,

Chinese: 
改性剂。 So from the class we could add
public here.但是，因为它是公开的
默认情况下，这不是必需的。 We could add
internal.内部意味着这门课程
公众在模块内。 So in our case,
because we're in a single module, this doesn't
改变一切。我们也可以将其设为私有。
Once we make it private, we'll now see that
it's no longer available in our main dotK
T file and this case a private class is only
available within the file in which it's implemented.
Now we get to apply similar rules to our nickname
property.如果我们将其作为内部财产，

English: 
nothing changes and we can still access that.
If we make this protected and go back to our
main function, we'll now see that we're getting
an air cannot access nickname. It is protected
in person. A protected property or method
will only be available within that class or
within any subclasses. And as you might expect,
if we make this a private property, once again,
we cannot access it from our main dot KT file.
And the same goes for our method. If we make
this private or protected, it's not going
to be available within main bat. K T now that
we have an understanding of how classes work
in Kotlin, let's take a look at how interfaces
work. So we'll go back to our source directory,
go to new Kotlin file or class. This time

Chinese: 
什么都没有改变，我们仍然可以访问它。
如果我们保护这个并回到我们的
main function, we'll now see that we're getting
an air cannot access nickname.它受到保护
亲自。 A protected property or method
will only be available within that class or
在任何子类中。 And as you might expect,
if we make this a private property, once again,
我们无法从主点KT文件中访问它。
我们的方法也是如此。如果我们做
this private or protected, it's not going
to be available within main bat. KT现在
we have an understanding of how classes work
in Kotlin, let's take a look at how interfaces
工作。 So we'll go back to our source directory,
go to new Kotlin file or class.这次

Chinese: 
in the kind drop down, we'll select the interface
and let's go ahead and call this person info
提供者，我们会打得好。
So now the IDE has created a person info provider
dotK T file and it's auto generated this empty
我们的人员信息提供者界面。现在，
like with the class, because the curly braces
are empty, we can actually remove those and
this is a completely valid interface within
科特林。这是医学博士。 There's no methods that can
be implemented and there are no properties
可以实施。 However, this could
still be used as a marker interface, for example,
in other classes, could in fact implement
this interface.事实上，为什么我们不这样做
马上？ Let's create a class called the
basic info provider, the implements person,

English: 
in the kind drop down, we'll select the interface
and let's go ahead and call this person info
provider and we'll hit okay.
So now the IDE has created a person info provider
dotK T file and it's auto generated this empty
person info provider interface for us. Now,
like with the class, because the curly braces
are empty, we can actually remove those and
this is a completely valid interface within
Kotlin. It's MD. There's no methods that can
be implemented and there are no properties
that can be implemented. However, this could
still be used as a marker interface, for example,
in other classes, could in fact implement
this interface. In fact, why don't we do that
right now? Let's create a class called the
basic info provider, the implements person,

Chinese: 
信息提供者。 We can actually do that within
the same file.我们不需要一个文件
Collin中的每个类或接口。所以
start we can say class basic info provider.
Now we want to indicate that this class is
going to implement person and vote provider.
To do that we'll use a colon and then we'll
type the name of the interface and just like
that, we've now created a new class basic
info provider that implements person info
供应商。 And because person info provider
does not currently have any methods or properties,
basic info provider has nothing that needs
to implement.哦，让我们为我们添加一个方法
人。信息提供者界面可以做到这一点
我们将回到接口声明，
we'll add back our braces, and now we're going
to define a function signature within this

English: 
info provider. We can actually do that within
the same file. We don't need to have one file
per class or interface within Collin. So to
start we can say class basic info provider.
Now we want to indicate that this class is
going to implement person and vote provider.
To do that we'll use a colon and then we'll
type the name of the interface and just like
that, we've now created a new class basic
info provider that implements person info
provider. And because person info provider
does not currently have any methods or properties,
basic info provider has nothing that needs
to implement. Oh, let's add a method to our
person. Info provider interface can do that.
We'll come back up to the interface declaration,
we'll add back our braces, and now we're going
to define a function signature within this

Chinese: 
接口。 Now we don't have to actually implement
this, we just have to define the name and
此方法所需的参数。
现在，一旦我们添加了这个，我们就会注意到了
below now that our basic info provider class
has a compiler error saying that it does not
implement the required interfaces or add the
abstract keyword.
So let's take a look at how we can address
this issue.你能，所以我们要开始了
off by adding a main function so that we can
play around with this class.现在是什么
the ways that we could solve the compile issue
with basic info provider is by declaring it
作为一个抽象类。 This means it doesn't
need to implement all the methods available
on the interfaces that includes, but it also
can't be instantiated.所以，如果我们试图来

English: 
interface. Now we don't have to actually implement
this, we just have to define the name and
the parameters that are required by this method.
Now once we've added this, we'll notice down
below now that our basic info provider class
has a compiler error saying that it does not
implement the required interfaces or add the
abstract keyword.
So let's take a look at how we can address
this issue. Could you, so we're going to start
off by adding a main function so that we can
play around with this class. Now what are
the ways that we could solve the compile issue
with basic info provider is by declaring it
as an abstract class. This means it doesn't
need to implement all the methods available
on the interfaces that includes, but it also
can't be instantiated. So if we tried to come

English: 
down here and say vow provider equals basic
info provider, we'll get an error saying cannot
create an instance of an abstract
class. So this case we don't want to make
this abstract cause we do want to work with
this class so we can remove the abstract class
keyword and that we want to actually implement
the required methods from person info provider.
So to do that we can start typing print info
and the IDE will recognize that. And if we
hit enter, it will generate a step down version
of that print info method.
Now let's take a look at how this was generated.
We see that it starts by including the override
key word. This is different than in Java where
it was an override annotation. And Caitlyn,
if you remove the override keyword, it'll
actually give you a compile error in this
case saying print info hides member of super
tight and needs the override modifier. So

Chinese: 
down here and say vow provider equals basic
info provider, we'll get an error saying cannot
创建一个抽象的实例
类。 So this case we don't want to make
this abstract cause we do want to work with
this class so we can remove the abstract class
keyword and that we want to actually implement
人员信息提供者所需的方法。
所以要做到这一点，我们可以开始输入打印信息
并且IDE将认识到这一点。 And if we
hit enter, it will generate a step down version
该打印信息方法。
现在让我们来看看它是如何生成的。
我们看到它首先包括覆盖
关键词。 This is different than in Java where
it was an override annotation.和凯特琳，
if you remove the override keyword, it'll
actually give you a compile error in this
case saying print info hides member of super
tight and needs the override modifier.所以

English: 
it's very specific in indicating that you
do need to include that override. And then
after that it's simply matches the rest of
the method declaration from the interface.
So here we're now free to define the behavior
of this interface, however we want you also
seen down below that now that we have implemented
the interface fully, we can actually create
an instance of this class. So if we implement
this right for now, just printing out print
info,
yeah,
we can come down to our main function, we
can type provider doc and then we can invoke
the print info method and we'll pass it in
a empty instance of the person class and we'll
see here that it executes that print info
method
[inaudible].

Chinese: 
it's very specific in indicating that you
do need to include that override.然后
after that it's simply matches the rest of
the method declaration from the interface.
So here we're now free to define the behavior
of this interface, however we want you also
seen down below that now that we have implemented
the interface fully, we can actually create
这个类的一个实例。 So if we implement
this right for now, just printing out print
信息，
是啊，
we can come down to our main function, we
can type provider doc and then we can invoke
the print info method and we'll pass it in
a empty instance of the person class and we'll
see here that it executes that print info
方法
[听不见的。

Chinese: 
So that's a very simple example of how we
can define an interface to find a method on
that interface, implement it, and then run
it on that.实施课程。让我们改进吧
在执行打印信息。所以
here we're going to say basic info provider
and then below that we're actually going to
call the print info method on our person class.
So now if we run this, we'll see that we have
that basic info provider being printed out
然后来自人的信息。 Now perhaps
we want to encapsulate this logic within the
界面本身。 Maybe this print info method,
it should always generally work in this same
办法。 Well, we could actually move the implementation
that we've just defined right here up into

English: 
So that's a very simple example of how we
can define an interface to find a method on
that interface, implement it, and then run
it on that. Implementing class. Let's improve
upon the implementation of print info. So
here we're going to say basic info provider
and then below that we're actually going to
call the print info method on our person class.
So now if we run this, we'll see that we have
that basic info provider being printed out
and then the info from the person. Now perhaps
we want to encapsulate this logic within the
interface itself. Maybe this print info method,
it should always generally work in this same
way. Well, we could actually move the implementation
that we've just defined right here up into

Chinese: 
our interface C and Kotlin interfaces provide
default implementation of an interface method.
So now we can actually remove the implementation
of print info from basic info provider and
代码仍将编译并运行。
So now if we run this, we're going to get
the same output.但是，有一个问题
有了这个。 We see now in our person info provider
interface, we are including the basic info
提供者字符串Well, we probably don't
want that since it is an implementation detail
基本信息提供者。 So here we could actually
leverage another interesting feature interfaces
在Kotlin。 We can provide properties on our
interfaces as well as methods.所以我们定义
一个名为strength类型的提供者信息的属性。
现在你可能想要给它一个默认值

English: 
our interface C and Kotlin interfaces provide
default implementation of an interface method.
So now we can actually remove the implementation
of print info from basic info provider and
the code will still compile and run.
So now if we run this, we're going to get
the same output. However, there's an issue
with this. We see now in our person info provider
interface, we are including the basic info
providers string. Well, we probably don't
want that since it is an implementation detail
of basic info provider. So here we could actually
leverage another interesting feature interfaces
in Kotlin. We can provide properties on our
interfaces as well as methods. So we'll define
a property called provider info of type strength.
Now you might be tempted to give this a default

Chinese: 
value, but if you do, you'll see that we actually
get a compiler error saying property initializers
不允许接口。 So you will
in fact have to override this and any implementing
类。 But now that we have this provider
info string, we could modify our print info
default implementation to print out that provider
信息。
So now we've kind of encapsulated this logic
into the interface itself.然后基本的
info provider class can now just override
that provider info property.我们覆盖
与方法大致相同的属性。
所以我们将使用覆盖誓言提供者信息类型
字符串然后我们必须提供getter。
所以在这种情况下我们会说基本的信息提供者。
And now if we run this once again that we'll
see that we are picking up the overwritten

English: 
value, but if you do, you'll see that we actually
get a compiler error saying property initializers
are not allowed to interfaces. So you will
in fact have to override this and any implementing
class. But now that we have this provider
info string, we could modify our print info
default implementation to print out that provider
info.
So now we've kind of encapsulated this logic
into the interface itself. And then the basic
info provider class can now just override
that provider info property. And we override
a property in much the same way as a method.
So we'll use override vow provider info type
string and then we have to provide the getter.
So in this case we'll say basic info provider.
And now if we run this once again that we'll
see that we are picking up the overwritten

Chinese: 
property value and then still relying on the
default implementation of print info in person
信息提供者。 And now if we wanted to still
override print info we could absolutely do
that and we could call through to the super
implementation if we would like and then we
can print out anything else here 
and if we were in this one last time we'll
see that we are now relying on the property,
the default implementation of print info as
well as now our additional logic and the overwritten
implementation of print info.接下来，我们来吧
look at how we can implement multiple interfaces
with a single class.首先，我们将添加一个

English: 
property value and then still relying on the
default implementation of print info in person
info provider. And now if we wanted to still
override print info we could absolutely do
that and we could call through to the super
implementation if we would like and then we
can print out anything else here 
and if we were in this one last time we'll
see that we are now relying on the property,
the default implementation of print info as
well as now our additional logic and the overwritten
implementation of print info. Next up, let's
look at how we can implement multiple interfaces
with a single class. To start we'll add a

English: 
new interface called session info provider
and then we'll add a method to those called
get session ID and that will return a string.
And so now if we come down to basic info provider,
we want to make this class implement session
info provider as well. Well I'll be asked
to do is to add a comma after the previous
interface declaration and now add session
info provider as well. And now once we do
that we'll now see you basic info provider
telling us that we don't implement the required
methods so we can come down here and implement
get session ID and we can return some session
ID. Now down here on our provider class, we
can now see that we can call get session ID

Chinese: 
新接口称为会话信息提供者
and then we'll add a method to those called
get session ID and that will return a string.
And so now if we come down to basic info provider,
we want to make this class implement session
信息提供者也是如此。 Well I'll be asked
to do is to add a comma after the previous
interface declaration and now add session
信息提供者也是如此。而现在我们做了
that we'll now see you basic info provider
telling us that we don't implement the required
methods so we can come down here and implement
get session ID and we can return some session
ID。 Now down here on our provider class, we
can now see that we can call get session ID

Chinese: 
在我们的基本信息提供者实例上Now's
a good time to talk about how type checking
和科特林的类型转换工作。 To do this
we're going to create a new function here
called check types and we're going to take
a parameter of type person info provider.
Now let's say that we want to check whether
this person info provider is also an instance
会话信息提供者。 How about we go
about doing that?好吧，我们可以说，如果信息
provider is session and vote provider and
then we'll print that out.说是一个会话
信息提供者。 Otherwise print Ellen, not
a session info provider and now we will call

English: 
on our basic info provider instance. Now's
a good time to talk about how type checking
and typecasting work in Kotlin. To do this
we're going to create a new function here
called check types and we're going to take
a parameter of type person info provider.
Now let's say that we want to check whether
this person info provider is also an instance
of a session info provider. How about we go
about doing that? Well we can say if info
provider is session and vote provider and
then we'll print that out. Say is a session
info provider. Otherwise print Ellen, not
a session info provider and now we will call

Chinese: 
this check types function and we'll pass in
our provider variable.所以现在如果我们运行这个
we'll see is a session invoke provider printed
到控制台。所以有条件的是
able to determine that the past in info provider
was also an instance of a session in both
供应商。 Now if we wanted to flip this logic
and check that it is not a session info provider,
we can add an exclamation point before that
and then we'll just flip these print statements
here and now once again if we run this we'll
see is a session in both providers.
So you have the flexibility there to check
that either way.现在让我们来看看

English: 
this check types function and we'll pass in
our provider variable. So now if we run this
we'll see is a session invoke provider printed
out to the console. So this conditional was
able to determine that the past in info provider
was also an instance of a session in both
provider. Now if we wanted to flip this logic
and check that it is not a session info provider,
we can add an exclamation point before that
and then we'll just flip these print statements
here and now once again if we run this we'll
see is a session in both providers.
So you have the flexibility there to check
that either way. Now let's take a look at

Chinese: 
类型转换是如何工作的。 So within this else
block we've already checked that info provider
是会话信息提供者。 So we can cast
it and then call methods on it as if it was
会话信息提供者。 So we could say info
provider as session info provider.作为
is the keyword used to cast something to another
type doc, get session ID.所以现在我们能够
to cast info provider is that session and
from a provider and call any methods or access
any properties on it that are specific to
session info provider.现在Caitlyn还包括
what is known as smart casting, which means
that if the compiler can check a type and
validate that that type will not change, then
you don't need to do any additional casting.
So in this case we've already validated that
info provider is a session info provider.

English: 
how typecasting works. So within this else
block we've already checked that info provider
is a session info provider. So we can cast
it and then call methods on it as if it was
a session info provider. So we could say info
provider as session info provider. The as
is the keyword used to cast something to another
type doc, get session ID. So now we're able
to cast info provider is that session and
from a provider and call any methods or access
any properties on it that are specific to
session info provider. Now Caitlyn also includes
what is known as smart casting, which means
that if the compiler can check a type and
validate that that type will not change, then
you don't need to do any additional casting.
So in this case we've already validated that
info provider is a session info provider.

Chinese: 
So we don't actually need to explicitly recast
这个。我们可以说info provider dot。得到
会话信息。 And the compiler is performing
a smart cast for us.所以在这里我们可以访问
get session ID or other properties and methods
on the session info provider without having
每次都明确地施展它。
We've never seen how a class can implement
multiple interfaces as an example of our basic
信息提供者。 Let's now take a look at how
a class can inherit from another existing
class and override methods and properties
on that base class.首先，让我们来创造
一个名为fancy info provider的新文件。 Within
this file we're going to create a new class

English: 
So we don't actually need to explicitly recast
this. We could say info provider dot. Get
session info. And the compiler is performing
a smart cast for us. So here we can access
get session ID or other properties and methods
on the session info provider without having
to explicitly cast it each time.
We've never seen how a class can implement
multiple interfaces as an example of our basic
info provider. Let's now take a look at how
a class can inherit from another existing
class and override methods and properties
on that base class. To start, let's create
a new file called fancy info provider. Within
this file we're going to create a new class

Chinese: 
称为花式信息提供者。 We didn't want
this class to extend the basic info provider
我们已经定义了。 So we can do that
by adding a colon and then typing the name
of the class that we want to inherit from
in this case basic info provider.现在很快
as I do this, you may notice that we have
a red squiggly line here indicating an error.
The error says this type is final, so it cannot
be inherited from this is a characteristic
of classes in Kotlin by default and Caitlyn
classes are closed, meaning they cannot be
继承或扩展。 To extend this
basic info provider class, we meet to add
the open keyword by adding the open keyword,
it now means that you can inherit from this
类。所以，如果我们回到我们的花哨信息

English: 
called fancy info provider. We didn't want
this class to extend the basic info provider
that we already defined. So we can do that
by adding a colon and then typing the name
of the class that we want to inherit from
in this case basic info provider. Now as soon
as I do this, you may notice that we have
a red squiggly line here indicating an error.
The error says this type is final, so it cannot
be inherited from this is a characteristic
of classes in Kotlin by default and Caitlyn
classes are closed, meaning they cannot be
inherited from or extended. To extend this
basic info provider class, we meet to add
the open keyword by adding the open keyword,
it now means that you can inherit from this
class. So if we go back to our fancy info

English: 
provider, you'll now see that our error has
gone away and we can now override methods
and properties in this class. Now let's start
by overriding the provider info property.
So we'll add the opening closed curly braces
to our class definition and then I can start
typing provider info and you'll see that the
IDE is suggesting the property available to
us to overwrite. So I'll hit enter and that
will go ahead and auto complete the property.
Now notice it has the override modifier indicating
that this property is being overridden and
I noticed that it automatically provides a
custom getter and you'll see that it defaults
to deferring to the super implementation of
this. So we could actually override this just

Chinese: 
provider, you'll now see that our error has
gone away and we can now override methods
和这个类中的属性。 Now let's start
by overriding the provider info property.
So we'll add the opening closed curly braces
to our class definition and then I can start
typing provider info and you'll see that the
IDE is suggesting the property available to
我们要覆盖。 So I'll hit enter and that
will go ahead and auto complete the property.
Now notice it has the override modifier indicating
that this property is being overridden and
I noticed that it automatically provides a
custom getter and you'll see that it defaults
to deferring to the super implementation of
这个。所以我们实际上可以覆盖它

Chinese: 
像这样通过说花哨的信息提供者。如果
we were to then come back to our main function
here and replace this with an instance of
fancy info provider and we rerun this, what
mousey is printing out fancy info provider
so that provider info is being correctly overwritten
在我们新的扩展课程中。
Now let's try overwriting the print info implementation
in our fancy info provider class.所以，如果我
start typing print info, once again, we'll
see the IDE suggesting the method that can
被覆盖。 I'll hit enter and again by
default this will call through to the super
implementation of print info within basic
信息提供者。所以我可以添加另一个
line here that just maybe says something like
fancy info.如果我回来跑我的

English: 
like this by saying fancy info provider. If
we were to then come back to our main function
here and replace this with an instance of
fancy info provider and we rerun this, what
mousey is printing out fancy info provider
so that provider info is being correctly overwritten
in our new extended class.
Now let's try overwriting the print info implementation
in our fancy info provider class. So if I
start typing print info, once again, we'll
see the IDE suggesting the method that can
be overwritten. I'll hit enter and again by
default this will call through to the super
implementation of print info within basic
info provider. And so I can then add another
line here that just maybe says something like
fancy info. And if I come back and run my

English: 
main function and that we'll see the base
implementation is the basic info provider
implementation. And now this extra line added
by our implementation of fancy info provider.
Now I want to illustrate one last point in
regards to inheritance, but before we do,
let's refactor basic info provider a little
bit. Instead of hard coding the session ID
here, let's add a property to hold that value.
So we'll come here and we'll say Val and we'll
say session IB prefix, let's say equals session.
And now we roll return session ID prefix right
here in our implementation of GIP session
ID. So now if I come into fancy info provider,
I want to override that new session info prefix.

Chinese: 
main function and that we'll see the base
implementation is the basic info provider
实现。 And now this extra line added
by our implementation of fancy info provider.
Now I want to illustrate one last point in
regards to inheritance, but before we do,
let's refactor basic info provider a little
位。而不是硬编码会话ID
在这里，让我们添加一个属性来保存该值。
所以我们会来到这里，我们会说Val和我们会
说会话IB前缀，让我们说等于会话。
现在我们滚动返回会话ID前缀吧
here in our implementation of GIP session
ID。所以现在如果我进入花哨的信息提供者，
我想覆盖新的会话信息前缀。

English: 
So to do that I might start typing session
and you'll notice that it's not auto suggesting
that new property that we just added. This
is because to overwrite a property and a derived
class, you have to Mark that property as open.
This is just like extending a class so we
can come here to session ID prefix and add
the open modifier as soon as we do that. If
we start typing once again, now we'll see
it's suggesting the option to override session
ID prefix. So just like the provider info
property, I can now override this and I can
say fancy session. So this is just one other
way in which Kotlin works to enforce immutability.
It forces you to Mark both your classes, your
properties, and your methods as being explicitly

Chinese: 
So to do that I might start typing session
and you'll notice that it's not auto suggesting
我们刚刚添加的新房产。这个
is because to overwrite a property and a derived
类，你必须将该属性标记为打开。
这就像扩展一个类，所以我们
can come here to session ID prefix and add
the open modifier as soon as we do that.如果
we start typing once again, now we'll see
it's suggesting the option to override session
ID前缀。 So just like the provider info
property, I can now override this and I can
说花哨的话。 So this is just one other
way in which Kotlin works to enforce immutability.
It forces you to Mark both your classes, your
properties, and your methods as being explicitly

English: 
open for extension. Now there's a small problem
with this new session ID prefix that we've
added.
It's really meant to be an implementation
detail of the class. However, if we come here
to our call site where we're using a fancy
info provider variable, you might notice that
we can actually access that prefix directly.
This isn't ideal because like I said, it's
an implementation detail. Our API shouldn't
really be exposing that property. Now the
reason it's available is because we have defined
it as a public property. So what can we do
about this? Well, if we want it to be available
and our child classes but not to the public
API, we could add the protected modifier.
So now that property is protected down here,

Chinese: 
开放延期。 Now there's a small problem
with this new session ID prefix that we've
添加。
It's really meant to be an implementation
detail of the class.但是，如果我们来这里
to our call site where we're using a fancy
info provider variable, you might notice that
我们实际上可以直接访问该前缀。
这并不理想，因为就像我说的那样
一个实现细节。 Our API shouldn't
really be exposing that property.现在
reason it's available is because we have defined
it as a public property.所以，我们能做些什么
对这个？ Well, if we want it to be available
and our child classes but not to the public
API，我们可以添加protected修饰符。
所以现在这里的财产受到保护，

Chinese: 
when we try to access it, we get an error
saying cannot access session ID prefix.和
if we come back to fancy info provider, you'll
see that we can still override that property
没有任何麻烦。
Now that we've explored how we can extend
an existing named class, let's look at how
we can create an instance of an anonymous
interclass using an object expression.至
去做。 We'll come over to our main function
here and now instead of instantiating an instance
of fancy info provider, we're going to create
an anonymous interclass.所以我们将删除它。
And to start off to create our object expression,
we can type object, colon and then the name
我们想要扩展的类。在这
case it'll be person info provider.现在在
这个课我们可以
覆盖任何可用的属性或方法。
所以在这种情况下，我将更新提供商信息

English: 
when we try to access it, we get an error
saying cannot access session ID prefix. And
if we come back to fancy info provider, you'll
see that we can still override that property
without any trouble.
Now that we've explored how we can extend
an existing named class, let's look at how
we can create an instance of an anonymous
interclass using an object expression. To
do that. We'll come over to our main function
here and now instead of instantiating an instance
of fancy info provider, we're going to create
an anonymous interclass. So we'll delete that.
And to start off to create our object expression,
we can type object, colon and then the name
of the class that we want to extend. In this
case it'll be person info provider. Now within
this class we can
override any available properties or methods.
So in this case I'll update the provider info

English: 
and just say something like new info provider.
Now notice below here that our provider dot
get session ID call is now being marked as
an error. That's because there is no guest
session ID on person info provider. But we
could go ahead and add a new method to our
object expression here. So we can just say
fun, get session, I ID equals and then we'll
just put in a value here. So you see you can
not only override the existing properties
and methods, but you can add to them as well.
Just like you could in any other name to class.
And now if we run this code, we'll see new
info provider being printed out to the screen.
So an object expression allows you to create
an anonymous inter class so you don't have

Chinese: 
并说一些像新的信息提供者。
现在请注意下面我们的提供者点
get session ID call is now being marked as
an error.那是因为没有客人
人员信息提供者的会话ID。 But we
could go ahead and add a new method to our
对象表达在这里。 So we can just say
fun, get session, I ID equals and then we'll
只是在这里输入一个值。 So you see you can
not only override the existing properties
和方法，但你也可以添加它们。
就像你可以用任何其他名字来上课一样。
And now if we run this code, we'll see new
info provider being printed out to the screen.
So an object expression allows you to create
an anonymous inter class so you don't have

Chinese: 
创建一个新的命名类。 So this might
be useful for things like a click listener.
If you were working in, let's say, Android
development.
Now that we've explored object expressions,
we're going to now look at companion objects.
And to do that, we're going to create a new
file and we're going to name that file entity
厂。 Now imagine we want to create a factory
to create instances of something called entity.
So to start we might create an entity class
and maybe that class will have a single ID
财产开始。 Now we want to make this
a factory like we said.那么我们可能想要什么
要做的是将此构造函数更改为私有。
现在，如果我们添加一个主要功能，我们

English: 
to create a new named class. So this might
be useful for things like a click listener.
If you were working in, let's say, Android
development.
Now that we've explored object expressions,
we're going to now look at companion objects.
And to do that, we're going to create a new
file and we're going to name that file entity
factory. Now imagine we want to create a factory
to create instances of something called entity.
So to start we might create an entity class
and maybe that class will have a single ID
property to start. Now we want to make this
a factory like we said. So what we might want
to do is change this constructor to be private.
And so now if we add a main function and we

Chinese: 
try to create an instance of entity, we'll
see that we have an issue here.请注意
that there is this error saying cannot access
在里面。它是私有的实体。所以这是
因为那个私人构造函数。好，
so what can we do?
This is where a companion object could come
in handy.伴侣对象是一个对象
范围限定为另一个类的实例。
所以在我们的块体内，我们可以输入
伴侣对象。 Now we could create a create
function called fun create and we'll have
它只是返回一个实体的实例。
现在我们只需将它传递给占位符
ID。 So now we can come back down to our main
function and we can type entity dot companion

English: 
try to create an instance of entity, we'll
see that we have an issue here. Well notice
that there is this error saying cannot access
in it. It is private to entity. So this is
because of that private constructor. Well,
so what can we do?
This is where a companion object could come
in handy. A companion object is an object
is scoped to an instance of another class.
So within our block body here, we can type
companion object. Now we could create a create
function called fun create and we'll have
that simply return an instance of entity.
And for now we'll just pass it in a placeholder
ID. So now we can come back down to our main
function and we can type entity dot companion

English: 
dot create. And we can use this to create
an instance of that class. This works because
companion objects have access to private properties
and methods of that in closing class. Now
in this case, we can actually shorten this
by removing the reference to companion altogether.
That new companion is implicit and if you're
using it from Kotlin, you can leave it off.
However, if you were using this companion
object from Java, you would have to reference
that companion object instance directly. You
can also rename your companion object. So
if we wanted to name this something like factory
to be a bit more explicit, we can then say
doc factory and reference it that way. And
so again, not needed from Kotlin but it could
be a good way to make your code more understandable
from the Java side of things. If you're doing

Chinese: 
点创建。 And we can use this to create
an instance of that class.这是因为
companion objects have access to private properties
and methods of that in closing class.现在
in this case, we can actually shorten this
by removing the reference to companion altogether.
That new companion is implicit and if you're
using it from Kotlin, you can leave it off.
However, if you were using this companion
object from Java, you would have to reference
那个伴随对象实例直接。您
can also rename your companion object.所以
if we wanted to name this something like factory
to be a bit more explicit, we can then say
doc工厂并以这种方式引用它。和
so again, not needed from Kotlin but it could
be a good way to make your code more understandable
from the Java side of things.如果你在做

English: 
a lot of Java to Kotlin interrupt, we can
also store properties within our companion
objects as well. So in this case we can create
a const thou well
ID equals IB and then we can come down here
and replace our entity and pass that in. Now
that we have this ID property added to our
companion object, we can reference it from
other calling code as if it was a static property
like we're familiar with from Java. So we
could do that by typing entity dot. And then
we can reference that ID property directly.
Now competing objects are like any other class
and that they can also implement other interfaces
to demonstrate that we'll create a new interface
called ID provider with a single method this

Chinese: 
a lot of Java to Kotlin interrupt, we can
also store properties within our companion
对象也是。 So in this case we can create
a const thou well
ID equals IB and then we can come down here
and replace our entity and pass that in. Now
that we have this ID property added to our
companion object, we can reference it from
other calling code as if it was a static property
like we're familiar with from Java.所以我们
可以通过输入实体点来做到这一点。然后
we can reference that ID property directly.
Now competing objects are like any other class
and that they can also implement other interfaces
to demonstrate that we'll create a new interface
called ID provider with a single method this

Chinese: 
叫得到ID。它将返回一个字符串。现在
then come down to our companion object declaration
and we can make it implement ID provider the
same way we would with any other class.我们
can then choose to implement the required
members and then here we will just return
a simple ID and so now when we create our
instance of ID, we could rely on this ID method
如果我们想要它。 So you see companion objects
can be quite flexible if you need them to.
You could use those to compose other types
of behavior, store your semi static properties
or methods and use them to create factories
by referencing private inner properties or
封闭类的方法。 This is really
what you would want to leverage if you want
功能类似于静态成员
来自Java世界的领域。 Now that
we've covered object expressions and companion

English: 
called get ID. It will return a string. Now
then come down to our companion object declaration
and we can make it implement ID provider the
same way we would with any other class. We
can then choose to implement the required
members and then here we will just return
a simple ID and so now when we create our
instance of ID, we could rely on this ID method
if we want it. So you see companion objects
can be quite flexible if you need them to.
You could use those to compose other types
of behavior, store your semi static properties
or methods and use them to create factories
by referencing private inner properties or
methods of the enclosing class. This is really
what you would want to leverage if you want
functionality similar to that of static members
and field from the world of Java. Now that
we've covered object expressions and companion

English: 
objects, let's take a look at creating an
object declaration. To start, we're going
to clean up some of this code we've been working
with so we will remove this implementation
of ID provider and we will go back to using
a placeholder ID. We'll remove this reference
to entity ID and we can remove this ID provider
interface. Now what our object declarations
and object declaration is a convenient way
of creating threads saved singletons within
Kotlin. We can do this by using the object
keyword and then a class name in this case
entity factory. Now within this you can add
any types of properties or methods that you
would like. So let's start by migrating our
create method from our companion object into

Chinese: 
objects, let's take a look at creating an
object declaration.首先，我们要走了
to clean up some of this code we've been working
with so we will remove this implementation
of ID provider and we will go back to using
a placeholder ID.我们将删除此引用
to entity ID and we can remove this ID provider
接口。现在我们的对象声明
and object declaration is a convenient way
of creating threads saved singletons within
科特林。 We can do this by using the object
keyword and then a class name in this case
实体工厂。 Now within this you can add
any types of properties or methods that you
想。 So let's start by migrating our
create method from our companion object into

English: 
heart entity factory and now we can remove
that companion object and instead we can reference
entity factory dot create.
Now there's one small problem with this so
far, which is that entity still has only a
private constructor. Now we're going to remove
that private modifier for now so that we can
use that constructor. However very shortly
we will continue to refactor this code to
limit the ways in which entities can be created.
Now before we go on and continue to explore
some of these other class types in Kotlin,
let's add to our entity class by implementing
two string so that if we print out an instance
of entity, we get some nice user readable
text. So we can start typing two string. And
then I'll use a string template here and we'll

Chinese: 
heart entity factory and now we can remove
that companion object and instead we can reference
实体工厂点创建。
Now there's one small problem with this so
far, which is that entity still has only a
私人建设者。 Now we're going to remove
that private modifier for now so that we can
使用那个构造函数。 However very shortly
we will continue to refactor this code to
限制实体的创建方式。
现在，在我们继续探索之前
some of these other class types in Kotlin,
let's add to our entity class by implementing
two string so that if we print out an instance
of entity, we get some nice user readable
文本。所以我们可以开始输入两个字符串。和
then I'll use a string template here and we'll

Chinese: 
说ID冒号是ID。 And then we will also
add in a name property here, Val name of type
串。
And then we'll say name and then substitute
in that main property.然后在我们的
create method we will just put in a generic
名称。现在我们可以使用打印件
line statement and pass in our instance of
实体。现在我们看到了新的两个流
正在打印到控制台的文本。所以
this will help us going forward demonstrate
some of how these other classes are going
上班。好了，现在我们可以打印了
out useful information about an instance of
an entity, let's refactor our create factory
method to actually differentiate instances
of entity.所以要做到这一点，我们将要改变

English: 
say ID colon is ID. And then we will also
add in a name property here, Val name of type
string.
And then we'll say name and then substitute
in that main property. And then here in our
create method we will just put in a generic
name. And now down here we can use a print
line statement and pass in our instance of
entity. And now we see our new two stream
texts being printed out to the console. So
this will help us going forward demonstrate
some of how these other classes are going
to work. All right, now that we can print
out useful information about an instance of
an entity, let's refactor our create factory
method to actually differentiate instances
of entity. So to do this, we're going to change

Chinese: 
this and make it no longer a single expression
功能。所以我们将添加一个返回类型
实体然后我们将添加一个return关键字。
那就是，我们将添加实体。现在第一个
thing you want to do here is actually add
a proper ID value.
So here you could say Val ID equals you do
ID dot random UU ID dot two string.所以这
will give us a new random identifier and then
we can pass that into our entity.但现在
我们有这个主要财产。 So what can we
do to pass in a name here?好吧一件事
we might do is think about differentiating
between different types of entities.所以
a very basic case, maybe you want to differentiate
between easy, medium, and hard difficulties
这些实体类型。 So we might want to
then have some way of passing or indicating

English: 
this and make it no longer a single expression
function. So we will add a return type of
entity and then we'll add a return keyword.
And that will, we'll add entity. Now the first
thing you want to do here is actually add
a proper ID value.
So here you could say Val ID equals you do
ID dot random U U ID dot two string. So this
will give us a new random identifier and then
we can pass that into our entity. But now
we have this main property. So what can we
do to pass in a name here? Well one thing
we might do is think about differentiating
between different types of entities. So in
a very basic case, maybe you want to differentiate
between easy, medium, and hard difficulties
of these entity types. So we might want to
then have some way of passing or indicating

English: 
to this factory method, what those different
types should be. So what am I, we could do,
this is with an ENM class. Now if you're familiar
with Java and Enim class is going to be very
similar to what you're familiar with from
[inaudible] in Java. To do that, we can start
typing email and then class. And then in this
case we might name this something like entity
type and open and closed curly braces. And
then we can iterate the different instances
of the email. So in this case we might say
easy, medium, hard. So now we can come down
here to our create method and then we can
add a type parameter of entity type.
And so now we could say vow name equals when
type. And then we are going to add in the

Chinese: 
to this factory method, what those different
types should be.那么我，我们能做什么呢
这是ENM课程。 Now if you're familiar
with Java and Enim class is going to be very
similar to what you're familiar with from
[inaudible] in Java.为此，我们可以开始
键入电子邮件然后上课。 And then in this
case we might name this something like entity
类型和开放和封闭的花括号。和
then we can iterate the different instances
电子邮件。 So in this case we might say
easy, medium, hard.所以现在我们可以下来了
here to our create method and then we can
add a type parameter of entity type.
And so now we could say vow name equals when
type.然后我们将添加

Chinese: 
剩下的分支。 So now we have a branch
for each of our entity types.然后为
a basic name, I'm just going to map these
to a string.所以说简单，中等和艰难。
所以现在我可以传递这个名字。所以现在
our factory method actually allows us to differentiate
并创建不同类型的实例。所以
down here we might start off by creating an
简单的实体，然后我们将打印出来。
然后我们可以说誓言中等实体等于
实体，工厂点。创建实体紧密的媒介。
然后我们也可以打印出来。

English: 
remaining branches. So now we have a branch
for each of our entity types. And then for
a basic name, I'm just going to map these
to a string. So say easy, medium and hard.
And so now I can pass in that name. So now
our factory method actually allows us to differentiate
and create different types of instances. So
down here we might start off by creating an
easy entity and then we'll print that out.
And then we might say vow medium entity equals
entity, factory dot. Create entity tight medium.
And then we can print that out as well.

Chinese: 
And if we run this well, now see that we have
a unique identifier for each entity.然后
we have the customized name based on that
entity type.所以增加了这个ENM类
to represent our entity type has allowed us
to pass in different types to our factory
method and then customize the way that those
entities are created by mapping the entity
输入名称。 Now in this case, we're mapping
the name very closely to the name of the actual
阶级本身。 So to make this a little bit
easier and more encapsulated, there's a couple
我们可以做的事情。所以第一件事
we could do is take advantage of the name
ITAM课程的财产。 So to do that,
we could reference our type dot nay.所以这
is referencing the name of that actual [inaudible]
类。如果我们运行这个，我们可以看到什么
这个名字看起来像。

English: 
And if we run this well, now see that we have
a unique identifier for each entity. And then
we have the customized name based on that
entity type. So the addition of this ENM class
to represent our entity type has allowed us
to pass in different types to our factory
method and then customize the way that those
entities are created by mapping the entity
type to a name. Now in this case, we're mapping
the name very closely to the name of the actual
class itself. So to make this a little bit
easier and more encapsulated, there's a couple
of things we could do. So the first thing
we could do is take advantage of the name
property on an ITAM class. So to do that,
we could reference our type dot nay. So this
is referencing the name of that actual [inaudible]
class. And if we run this, we can see what
that name looks like.

English: 
So you see it's easy all in capital letters.
This matches exactly the way that the class
name is actually defined. So this allows us
to reference the classes name directly without
having to map it manually. Now this is nice,
however, we don't have a lot of control over
the formatting here. So another thing we could
do is actually add a new method to argue in
class. So in this case we get add fun, get
formatted name, and then we can reference
that named property.to lowercase dot capitalize.
So this will return us that preform at a name
and capitalize the first letter. So now down
here we can update our medium mapping and
type type dot get format in name. And so now
if we run this code again, we'll see that

Chinese: 
因此，您可以看到所有大写字母都很容易。
这与该类的方式完全匹配
名称实际上已定义。 So this allows us
to reference the classes name directly without
必须手动映射。 Now this is nice,
however, we don't have a lot of control over
这里的格式。 So another thing we could
do is actually add a new method to argue in
类。 So in this case we get add fun, get
formatted name, and then we can reference
将property.to命名为小写点大写。
所以这将使我们以一个名字进行预制
并将第一个字母大写。 So now down
here we can update our medium mapping and
type type dot get name in name。 And so now
if we run this code again, we'll see that

Chinese: 
the first one by using the name property directly
is all capitalized.但现在通过使用我们的新
format and method, we have a nicer format
similar to what we were using before.所以那是
just one example of how you can define an
Enon class and then add additional properties
and methods that class like you would any
other class.
Now let's continue refactoring this code to
further differentiate between different types
实体To do that, we're going to leverage
a sealed class seal classes allow us to define
受限制的类层次结构。 What this means
is that we could define a set number of classes
all extending a base type, but those classes
will be the only ones that can extend that
基础类型。 So one example of this could be
a loading state or results state for a network
操作。 It's either going to succeed or
fail and there aren't really any other options.

English: 
the first one by using the name property directly
is all capitalized. But now by using our new
format and method, we have a nicer format
similar to what we were using before. So that's
just one example of how you can define an
Enon class and then add additional properties
and methods that class like you would any
other class.
Now let's continue refactoring this code to
further differentiate between different types
of entities. To do that, we're going to leverage
a sealed class seal classes allow us to define
restricted class hierarchies. What this means
is that we could define a set number of classes
all extending a base type, but those classes
will be the only ones that can extend that
base type. So one example of this could be
a loading state or results state for a network
operation. It's either going to succeed or
fail and there aren't really any other options.

English: 
So in the right place we're going to create
a sealed class with an easy, medium, hard
and help entity types. To start creating our
sealed class hierarchy. We're first going
to remove the properties from our entity class
as well as this existing override of the two
string method. The next step is to add the
sealed keyword before the class keyword in
the entity class declaration.
As soon as we do that, we'll start getting
an error above where we tried to create an
instance of entity. This is because you can't
instantiate based sealed class type directly.
So this is now where we will create each type
within our sealed class hierarchy. So the
first type we're going to create is a David
class to represent easy entities. And then
we will add the properties we want in this
case the ID and name, and then we want to

Chinese: 
So in the right place we're going to create
a sealed class with an easy, medium, hard
和帮助实体类型。 To start creating our
sealed class hierarchy.我们先去
to remove the properties from our entity class
as well as this existing override of the two
字符串方法。 The next step is to add the
sealed keyword before the class keyword in
实体类声明。
As soon as we do that, we'll start getting
an error above where we tried to create an
实体的实例。 This is because you can't
instantiate based sealed class type directly.
So this is now where we will create each type
within our sealed class hierarchy.所以
first type we're going to create is a David
class to represent easy entities.然后
we will add the properties we want in this
case the ID and name, and then we want to

Chinese: 
确保我们从实体继承。所以
next up we can copy that and update the name
对于中型。 And now for the third
type, once again we'll copy that, we'll name
this hard, but now we're going to add an additional
property.此属性将被称为乘数
and we'll be afloat and this can represent
some type of difficulty, multiple fire if
我们正在制作一个游戏。
Now notice that all of these types within
the sealed class all extend from entity but
有不同类型的属性。这是
one of the key differentiators between sealed
课程和[听不清]课程。 With seal
classes, you can have different properties
and methods on each of these type and the
compiler can perform smart casting to allow
you to use these different properties and
methods as you would like.我们也可以使用
different types of classes itself within our
sealed class.所以你注意到这些是

English: 
make sure that we inherit from entity. So
next up we can copy that and update the name
for the medium type. And now for the third
type, once again we'll copy that, we'll name
this hard, but now we're going to add an additional
property. This property will be called multiplier
and we'll be afloat and this can represent
some type of difficulty, multiple fire if
we were creating a game for example.
Now notice that all of these types within
the sealed class all extend from entity but
have different types of properties. This is
one of the key differentiators between sealed
classes and [inaudible] classes. With seal
classes, you can have different properties
and methods on each of these type and the
compiler can perform smart casting to allow
you to use these different properties and
methods as you would like. We can also use
different types of classes itself within our
sealed class. So you notice that these are

Chinese: 
全部作为数据类创建。 However, if we
wanted to remove data from one of these, that
会很好。 We could also use
object declarations within our seal class
层次结构。 So this case will create an object
class called help to represent some type of
我们程序中的通用静态帮助实体。
现在因为help没有构造函数
因为它是静态的。 In this case, we can
add a class body and we could add a name and
直接添加帮助。 And in this case, more
ad ID.因为它是一个单身人士而且有
反正永远只会是一个例子，
now that we have our seal classes defined,
we're going to update our factory method to
instantiate and return different types of
entity classes.所以我们会来到我们这里
return statement and instead of returning
an entity directly, we're going to use a wind

English: 
all created as data classes. However, if we
wanted to remove data from one of these, that
would be perfectly fine. We could also use
object declarations within our seal class
hierarchy. So this case will create an object
class called help to represent some type of
generic static help entity within our program.
Now because help doesn't have a constructor
because it's static. In this case, we can
add a class body and we could add a name and
add help directly. And in this case, more
ad ID. Since it's a Singleton and there's
only going to ever be one instance anyways,
now that we have our seal classes defined,
we're going to update our factory method to
instantiate and return different types of
entity classes. So we'll come up here to our
return statement and instead of returning
an entity directly, we're going to use a wind

English: 
expression based on the entity type being
in class. We'll then add all of the needed
branches. And so when we have an easy type,
we want to instantiate an instance of the
easy class. So to do that we'll type D Z and
then we will pass an ID and name. And similarly
for media type, entity dot. Media ID, combat
name. And now for hard, once again we'll pass
it and entity dot hard ID name. But now again
we have this additional property type and
the compiler recognizes that. So for now we'll
just pass it in to F as our multiplier.
Now notice though that we have this help entity
being unused. So let's update the factory
to allow us to create instances of the help
type. So we'll come up to our entity type

Chinese: 
expression based on the entity type being
in class.然后我们将添加所有需要的内容
分支机构。 And so when we have an easy type,
we want to instantiate an instance of the
轻松上课。 So to do that we'll type DZ and
then we will pass an ID and name.同样地
对于媒体类型，实体点。 Media ID, combat
名称。现在很难，我们将再次通过
它和实体点硬ID名称。 But now again
we have this additional property type and
编译器认识到这一点。 So for now we'll
just pass it in to F as our multiplier.
Now notice though that we have this help entity
being unused.所以让我们更新工厂
to allow us to create instances of the help
type.所以我们将来到我们的实体类型

English: 
Unum class and add a help type here. Now notice
as soon as we added that additional type on
the entity type in them class are when expressions
one to us that we need to add an additional
branch. So to do that, I'll add the remaining
branch here and I'll default to typed up get
format name. And once again below here I'll
add the remaining branch. And in this case
I'm just going to return help directly.
Oh, notice here that help is giving us an
error. It's saying required and to be found
entity that help. This was done to demonstrate
what happens if you do not extend from the
base entity type. So if we come down to our
entity class here and you notice our object

Chinese: 
Unum类并在此处添加帮助类型。 Now notice
as soon as we added that additional type on
the entity type in them class are when expressions
one to us that we need to add an additional
科。 So to do that, I'll add the remaining
branch here and I'll default to typed up get
格式名称。 And once again below here I'll
add the remaining branch.在这种情况下
我只是想直接回复帮助。
Oh, notice here that help is giving us an
error.它说要求和被发现
帮助的实体。 This was done to demonstrate
what happens if you do not extend from the
基本实体类型。 So if we come down to our
entity class here and you notice our object

English: 
declaration for help, if we then add a colon
entity to extend from entity, we'll now see
that error go away. So this is a good example
of how the compiler can help give us this
nice static type checking and all of these
things. And if we are combining even classes
was sealed classes with these, when expressions
get allows us to be sure that if we add a
new type or a new branch somewhere that we
have to handle that effectively because the
compiler will warn us or even give errors
if we're not handling all of those different
branches. Now let's come down to our main
function and demonstrate one of the advantages
of representing our entities as a seal class
hierarchy.
So if I remove everything, but this first
instance of creating an entity, I'm going
to specifically add a type here of entity.
And so now if we, if we come down again, we

Chinese: 
declaration for help, if we then add a colon
entity to extend from entity, we'll now see
那个错误消失了。 So this is a good example
of how the compiler can help give us this
nice static type checking and all of these
的东西。如果我们正在组合甚至班级
was sealed classes with these, when expressions
get allows us to be sure that if we add a
new type or a new branch somewhere that we
have to handle that effectively because the
compiler will warn us or even give errors
if we're not handling all of those different
分支机构。 Now let's come down to our main
function and demonstrate one of the advantages
of representing our entities as a seal class
层次结构。
So if I remove everything, but this first
instance of creating an entity, I'm going
在这里专门添加一个实体类型。
所以现在如果我们，如果我们再次下来，我们

Chinese: 
can use a one expression and we'll say, now
we can go down here and use a wet expression
to do some type checking about the entity
that we have just instantiated.所以我们在这里
说Val，消息等于实体。现在
again we're going to rely on the IBE to add
所有剩余的分支机构。 So there's a few
things of interest to note here.所以我们会
see that for an easy, medium and hard, it's
adding.这是检查。所以这是
basically tell if it's an instance of that
class or not.但随后请注意帮助
class, because that's an object declaration
and as a Singleton there's no need to have
它是。
So in that case we can reference that class
直。所以现在我们可以添加任何内容

English: 
can use a one expression and we'll say, now
we can go down here and use a wet expression
to do some type checking about the entity
that we have just instantiated. So here we'll
say Val, message equals when entity. And now
again we're going to rely on the IBE to add
all the remaining branches. So there's a few
things of interest to note here. So we'll
see that for an easy, medium and hard, it's
adding. This is check. So this is going to
basically tell if it's an instance of that
class or not. But then notice for the help
class, because that's an object declaration
and as a Singleton there's no need to have
it is.
So in that case we can reference that class
directly. And so now here we could add whatever

Chinese: 
我们想要的消息。 So we could say help class,
easy class, medium class and hard class.和
then if we simply print that message out and
run the code, we can see in this case we're
轻松上课。 And then if we change
what we pass into our factory method and rerun
this, well now see that we're getting the
help class.所以现在我们有静态类型检查
both and specifying what type of entity we
want back and and checking the type that we're
实际上是从那里回来的。所以我们
could use this to then call any methods or
特定于该类的属性。
如果我们按照这些类型进行操作
in a one expression here, if we ever added
a new type, that compiler would be sure to

English: 
message we wanted. So we could say help class,
easy class, medium class and hard class. And
then if we simply print that message out and
run the code, we can see in this case we're
getting an easy class. And then if we change
what we pass into our factory method and rerun
this, well now see that we're getting the
help class. So now we have static type checking
both and specifying what type of entity we
want back and and checking the type that we're
actually getting back from that. And so we
could use this to then call any methods or
properties that are specific to that class.
And if we were operating on these types as
in a one expression here, if we ever added
a new type, that compiler would be sure to

English: 
make sure that we handled the addition of
that new type.
So now let's return to our sealed class hierarchy
for a second and dive more deeply into what
data classes are. So you see here both easy
and medium and hard are all defined as data
classes. Data classes are cotton's way of
providing very concise, immutable data types.
By defining a class as a data class, it means
that it is going to generate methods such
as equals hashcode into string automatically
for you. What this allows us to do is perform
a quality comparisons on instances of these
data classes and treat them as equal if the
data they contain is equal. So here's an example.
Let's explore what this looks like. So we
can say Val entity one equals entity factory
that create and will create an easy entity.

Chinese: 
make sure that we handled the addition of
that new type.
So now let's return to our sealed class hierarchy
for a second and dive more deeply into what
数据类是。 So you see here both easy
and medium and hard are all defined as data
类。 Data classes are cotton's way of
providing very concise, immutable data types.
By defining a class as a data class, it means
that it is going to generate methods such
as equals hashcode into string automatically
为了你。这让我们能做的就是表演
a quality comparisons on instances of these
data classes and treat them as equal if the
它们包含的数据是相同的。所以这是一个例子。
让我们来探索一下它的样子。所以我们
can say Val entity one equals entity factory
that create and will create an easy entity.

Chinese: 
And then we're going to create another version
这个的。然后我们现在可以检查他们的平等
比较。
So you can say if entity one equals entity
two per DeLeon, they are equal else per Delon,
他们不等于。 Now if we run this,
what will we see?他们不平等。和
这是预期的。 That's because if
we come back up to our factory, we'll notice
that we are creating different unique ideas
each time.所以尽管这个名字是
同样，唯一ID也不同。所以现在
let's update this and see what it looks like
if we pass the same data in. So in this case
we could create an easy directly and this

English: 
And then we're going to create another version
of this. And then now we can check their equality
comparison.
So you can say if entity one equals entity
two per DeLeon, they are equal else per Delon,
they are not equal to. Now if we run this,
what will we see? They are not equal. And
that's to the expected. That's because if
we come back up to our factory, we'll notice
that we are creating different unique ideas
each time. So even though that the name is
the same, the unique ID is different. So now
let's update this and see what it looks like
if we pass the same data in. So in this case
we could create an easy directly and this

English: 
case will pass in ID comma name and then we
will duplicate this for entity two. And so
now if we run this, we're going to expect
to see you. They are equal and of course they
are. So this is really convenient. This allows
us to represent data within our applications
and compare this data no matter where it comes
from.
And as long as those properties are all the
same, we're going to be able to evaluate these
as true. Now another really interesting thing
that data classes give us are effective copy
constructors. So we can create an instance
of entity two by copying entity one entity,
one dot copy. And because this is a direct
copy, if we run this once again, we're going
to see they are equal. However, we could also
use named arguments with the copy constructor

Chinese: 
case will pass in ID comma name and then we
will duplicate this for entity two.所以
now if we run this, we're going to expect
to see you.他们是平等的，当然也是他们
是。所以这真的很方便。 This allows
us to represent data within our applications
and compare this data no matter where it comes
from.
And as long as those properties are all the
same, we're going to be able to evaluate these
是的。 Now another really interesting thing
that data classes give us are effective copy
构造函数。 So we can create an instance
of entity two by copying entity one entity,
一个点副本。 And because this is a direct
copy, if we run this once again, we're going
看他们是平等的。 However, we could also
use named arguments with the copy constructor

English: 
to change the value. So let's say we only
wanted to change the BAME and you could say
name equals new name. And once again, if we
rerun this, we're going to see they are not
equal. So you could see changing a single
property and the data class is going to impact
whether or not two instances evaluate to true
or not when compare.
Now one thing to notice is this is comparing
the value of the data themselves. If we wanted
to U S referential comparison, we hit add
a third equal sign here and this will check
whether or not it's the exact same reference
or not. So in this case they are not equal.
However, this isn't all that surprising since
the data was also equal. So what about if
we revert this and make this an exact copy
again? So before if we were just using two

Chinese: 
改变价值。 So let's say we only
wanted to change the BAME and you could say
name等于新名称。 And once again, if we
rerun this, we're going to see they are not
等于。 So you could see changing a single
property and the data class is going to impact
whether or not two instances evaluate to true
or not when compare.
Now one thing to notice is this is comparing
the value of the data themselves.如果我们想要
to US referential comparison, we hit add
a third equal sign here and this will check
whether or not it's the exact same reference
or not.所以在这种情况下他们并不平等。
However, this isn't all that surprising since
the data was also equal.那么如果
we revert this and make this an exact copy
再次？所以，如果我们只是使用两个

Chinese: 
等号，数据会是一样的。所以
it would print, they are equal.但是，通过
using three equal signs and using referential
equality, we see they are not equal.那是
because it's not the same exact reference
of the object.如果我们将此更新为实体
one equal equal equals entity one and run
this, now we'll see they are equal.
So that's just one way in which we can check
whether or not we have the exact same object
or if it's two different objects that have
the same data.现在也要记住这一点
these equality comparisons are working off
of the generated equals and hash code methods
generated by the compiler when indicating
a data class.但是，我们可以更新这个
to change how the equals or hash code is evaluated
and to do that we would do it like any other

English: 
equal sign, the data would be the same. So
it would print, they are equal. However, by
using three equal signs and using referential
equality, we see they are not equal. That's
because it's not the same exact reference
of the object. If we updated this to be entity
one equal equal equals entity one and run
this, now we'll see they are equal.
So that's just one way in which we can check
whether or not we have the exact same object
or if it's two different objects that have
the same data. Now also keep in mind that
these equality comparisons are working off
of the generated equals and hash code methods
generated by the compiler when indicating
a data class. However, we could update this
to change how the equals or hash code is evaluated
and to do that we would do it like any other

English: 
class. We could add a class body and then
we could simply override equals and or hash
code. Now as in Java best practice, if you're
going to override one of these, you should
really override both of them and you have
to follow the same rules, but you have that
freedom if you would like to.
Another really useful feature in Kotlin is
the ability to define extension functions
or extension properties on an existing class.
This is particularly powerful if you're working
with classes that you can't control but would
like to modify the way in which they're used.
You can define your own properties and methods
and defined kind of a new API around the existing
class. So an example of this would be adding
a new method to the medium class without actually

Chinese: 
类。 We could add a class body and then
we could simply override equals and or hash
码。 Now as in Java best practice, if you're
going to override one of these, you should
really override both of them and you have
to follow the same rules, but you have that
如果你愿意，那就是自由。
Another really useful feature in Kotlin is
the ability to define extension functions
或现有类的扩展属性。
如果你正在工作，这个功能特别强大
with classes that you can't control but would
like to modify the way in which they're used.
You can define your own properties and methods
and defined kind of a new API around the existing
类。 So an example of this would be adding
a new method to the medium class without actually

English: 
defining that method within the definition
of the medium class. So to do that, let's
come down here and you can start off by typing
the fun keyword. And then instead of directly
typing the method name, we can reference the
class name. Dot. And this case will type print
info.
And then we can define our function buddy.
So in this case we'll just say medium class
with the ID and that'll be it. And so if we
wanted to come down here and now create an
instance of entity dot medium directly, we
could do that. And then we could call that

Chinese: 
defining that method within the definition
of the medium class.所以，要做到这一点，让我们
come down here and you can start off by typing
the fun keyword.而不是直接
typing the method name, we can reference the
class name.点。这种情况将打印
信息。
然后我们可以定义我们的函数伙伴。
所以在这种情况下我们只会说中产阶级
有了ID，那就是它。 And so if we
wanted to come down here and now create an
instance of entity dot medium directly, we
could do that.然后我们可以称之为

Chinese: 
打印信息方法。 And if we run that code,
we'll see a medium class and then that ID
打印出来。 So this is great if we know that
we have that exact type that we're working
用。 And in cases where we don't know if
we have that direct type, we could rely on
智能铸造。 So if we update this to you,
their factory say entity factory, create entity
中型。 Now we can say if entity two
is medium entity, now we can reference that
新的打印信息方法。
This is done because the if statement will
only evaluate to true if that cast is successful.
So anywhere within that context it will automatically
perform the smart cast for us.和我一样

English: 
print info method. And if we run that code,
we'll see a medium class and then that ID
printed out. So this is great if we know that
we have that exact type that we're working
with. And in cases where we don't know if
we have that direct type, we could rely on
smart casting. So if we update this to you,
their factory say entity factory, create entity
type medium. Now we can say if entity two
is medium entity, now we can reference that
new print info method.
This is done because the if statement will
only evaluate to true if that cast is successful.
So anywhere within that context it will automatically
perform the smart cast for us. And like I

English: 
said before, not only can we define extension
methods, but we can also define extension
properties as well. To do that, we could start
off by saying Val or VAR. In this case we'll
say vow and then again we'll reference the
class type. So medium dot we'll say info will
be this property name string equals some info.
If you do that, notice that we have this air.
If you look, it says extension property cannot
be initialized because it has no backing field.
So to actually create an extension of property
for an existing class, you need to rely on
backing fields. Thankfully the IDE can generate
this forest, convert extension property initializer
to a getter.
So once we do that and notice here that we
have still defined our property but now we're
relying on this custom getter for that property
and so now if we come back down here within

Chinese: 
said before, not only can we define extension
methods, but we can also define extension
属性也是。 To do that, we could start
off by saying Val or VAR.在这种情况下，我们会
say vow and then again we'll reference the
class type.所以中等点我们会说信息会
是这个属性名称字符串等于一些信息。
如果你这样做，请注意我们有这种空气。
If you look, it says extension property cannot
be initialized because it has no backing field.
So to actually create an extension of property
for an existing class, you need to rely on
支持领域。 Thankfully the IDE can generate
this forest, convert extension property initializer
一个吸气剂。
So once we do that and notice here that we
have still defined our property but now we're
relying on this custom getter for that property
and so now if we come back down here within

Chinese: 
our, if statement that's doing our smart cast
for us, we could reference that new info property
直。 So this is how extension functions
and properties work.你可以随时使用这些
you want to add additional functionality to
existing class.你可能会注意到
Kotlin standard library that many functions
and operations work by using extension functions
in classes be are particularly effective when
using them with template ID types
because it allows you to define the same common
functionality across any type that matches
那个模板。 Now up until this point, we've
covered a lot of things.我们看过了
basic type system of Kotlin, how to work with
different variable types, how to work with
basic functions and then diving into more
advanced functional topics like named arguments

English: 
our, if statement that's doing our smart cast
for us, we could reference that new info property
directly. So this is how extension functions
and properties work. You could use these anytime
you want to add additional functionality to
existing class. You might notice within the
Kotlin standard library that many functions
and operations work by using extension functions
in classes be are particularly effective when
using them with template ID types
because it allows you to define the same common
functionality across any type that matches
that template. Now up until this point, we've
covered a lot of things. We've looked at the
basic type system of Kotlin, how to work with
different variable types, how to work with
basic functions and then diving into more
advanced functional topics like named arguments

English: 
and default parameter values. And then we
took a deep dive into modeling data with Kotlin.
So now I'm going to circle back to functions
and specifically take a look at higher order
functions and how to work with functional
data types. Now what are higher order functions?
Higher order functions are functions that
either return another function or that take
functions as perimeter values. Now much of
Kotlin standard library is built on top of
higher order functions and it's what really
allows us to write highly functional code
by leveraging that standard library.
So let's take a look at how we can write our
own higher order function. To start we have
a new Kotlin file and we're going to define
a new function. So we'll call this fun. And
then we're going to call this print filtered
strengths. And now the first argument to this
is going to be a list of strings. So we'll
call this list and then define it as list

Chinese: 
和默认参数值。 And then we
took a deep dive into modeling data with Kotlin.
So now I'm going to circle back to functions
and specifically take a look at higher order
functions and how to work with functional
data types.现在什么是高阶函数？
Higher order functions are functions that
either return another function or that take
作为周界值起作用。 Now much of
Kotlin standard library is built on top of
higher order functions and it's what really
allows us to write highly functional code
通过利用该标准库。
So let's take a look at how we can write our
own higher order function.我们开始了
a new Kotlin file and we're going to define
a new function.所以我们称之为有趣。和
then we're going to call this print filtered
strengths.现在是第一个论点
将成为一个字符串列表。所以我们会
call this list and then define it as list

Chinese: 
的字符串。 And now the next thing we're going
to do is define a parameter which will in
事实上是一个功能。 That function will take
in a string and return a bullying.我们可以
then use that to filter out values in the
past collection.所以要定义一个函数参数，
you could start off by defining the parameter
name as usual.在这种情况下，我们将其命名
信用卡套件，其次是冒号。 And now you
have to define the type as you normally would
定义功能类型。
您可以先添加括号。
这将定义函数的参数
传入你的其他功能。所以
in this case we are going to take a string.
He'll then add the arrow, and then you want
to define the return type.所以在这种情况下，
这将是欺凌。 And now we'll add the
open and closed curly braces to define our

English: 
of string. And now the next thing we're going
to do is define a parameter which will in
fact be a function. That function will take
in a string and return a bullying. We can
then use that to filter out values in the
past collection. So to define a function parameter,
you could start off by defining the parameter
name as usual. And this case, we'll name it
credit kit, followed by colon. And now you
have to define the type as you normally would
to define a functional type.
You can start by adding your parentheses.
This will define the parameters of the function
being passed in to your other function. So
in this case we are going to take a string.
He'll then add the arrow, and then you want
to define the return type. So in this case,
that will be bullying. And now we'll add the
open and closed curly braces to define our

Chinese: 
块体。 So now we have a parameter called
predicate, which will be a function that takes
在字符串参数中并返回一个布尔值。
现在我们可以实现打印过滤的字符串了
function to make use of that predicate function
to filter out any strings in that past list.
So to implement this function, first off,
we want to iterate over each string in the
过去的清单。 So to do that, we could say list
doc for each and now we will be able to iterate
在每个字符串上。
So now what we want to do is evaluate the
predicate for each stream in the collection.
So we can call the predicate function in several
不同的方法。所以开始我们会说，如果，
and then the easiest way to invoke the predicate
is to simply say predicate open and close

English: 
block body. So now we have a parameter called
predicate, which will be a function that takes
in a string parameter and returns a Boolean.
Now we can implement our print filtered strings
function to make use of that predicate function
to filter out any strings in that past list.
So to implement this function, first off,
we want to iterate over each string in the
past list. So to do that, we could say list
doc for each and now we will be able to iterate
over each of those strings.
So now what we want to do is evaluate the
predicate for each stream in the collection.
So we can call the predicate function in several
different ways. So to start we'll say if,
and then the easiest way to invoke the predicate
is to simply say predicate open and close

Chinese: 
括号并传入参数值。
作为功​​能类型的参数可以
被称为好像是常规功能。
只要你能满足所需的参数。
So in this case we can say if predit kit returns
true, then we can print out that string.现在
to test this, we'll come down here and we
will add a main function and we will say vow
list equals list of, and then we can say something
like Kotlin, Java C plus plus Java script.
And now we could call print filtered strings
pass in our list.
And now we need to pass in a function as the
second parameter to print filters, drinks.
So we can do that by specifying a Lambda,
and in this case we will say it starts with

English: 
parentheses and pass in the parameter value.
A parameter that is a functional type can
be called as if it was a regular function.
As long as you can satisfy the required arguments.
So in this case we can say if predit kit returns
true, then we can print out that string. Now
to test this, we'll come down here and we
will add a main function and we will say vow
list equals list of, and then we can say something
like Kotlin, Java C plus plus Java script.
And now we could call print filtered strings
pass in our list.
And now we need to pass in a function as the
second parameter to print filters, drinks.
So we can do that by specifying a Lambda,
and in this case we will say it starts with

Chinese: 
K. so this Lambda is going to evaluate to
true if any of the past strings begins with
a K. now if we run this function, we'll see
only Kotlin print it out to the screen.如果
we were to update this to print things out,
that started with a J, well now see Java script
和Java。 Now one thing to notice is it in
our invocation of print filtered strings,
we've passed our Lambda within the parentheses
of that function in vacation.但是，这个
是我们不必做的事情。如
we mentioned earlier, we can take use of Landus
syntax, which says that if the last parameter
of a function is a function, you can specify
那个作为函数体外的Lambda。
所以我们可以重构我们的功能
像这样。 We can pass in the list first and
then specify or Lambda outside of the parentheses.

English: 
K. so this Lambda is going to evaluate to
true if any of the past strings begins with
a K. now if we run this function, we'll see
only Kotlin print it out to the screen. If
we were to update this to print things out,
that started with a J, well now see Java script
and Java. Now one thing to notice is it in
our invocation of print filtered strings,
we've passed our Lambda within the parentheses
of that function in vacation. However, this
is something that we don't have to do. As
we mentioned earlier, we can take use of Landus
syntax, which says that if the last parameter
of a function is a function, you can specify
that as a Lambda outside the function body.
So we can restructure our function to look
like this. We can pass in the list first and
then specify or Lambda outside of the parentheses.

English: 
So this is actually very similar looking to
the for each function which we called up above.
And in fact if you look at the implementation
of for each is in fact a higher order function.
The Lambda that we specify after invoking
for each is a function which will operate
over each string and that list. Now if we
come back up here to our implementation notice
we are calling the function parameter directly
as if it was a regular function. So this works
absolutely great in most situations. However,
if we were to make this function, type a NOLA
ball type by wrapping it in parentheses and
adding new question Mark. Well now see an
error in our implementation of print filtered
strings. That error basically says that you
cannot invoke that function parameter by using
the parentheses directly. If it's a nullable

Chinese: 
So this is actually very similar looking to
the for each function which we called up above.
And in fact if you look at the implementation
of for each is in fact a higher order function.
The Lambda that we specify after invoking
for each is a function which will operate
在每个字符串和该列表上。 Now if we
come back up here to our implementation notice
we are calling the function parameter directly
as if it was a regular function.这样可行
绝大多数情况下都很棒。然而，
if we were to make this function, type a NOLA
ball type by wrapping it in parentheses and
adding new question Mark.那么现在看一个
error in our implementation of print filtered
strings.那个错误基本上就是说你
cannot invoke that function parameter by using
the parentheses directly.如果它是可空的

Chinese: 
type to get around this, we can make use of
the invoke method on that functional type
and then we can make use of the safe call
operator and now, but updating this to do
对谓词函数的安全调用调用。
We can handle this rather not the predicate
is no calling invoke will invoke the function
just as it would any other indication of a
功能。所以现在这里没有任何改变
以及我们如何调用打印过滤字符串。
但是，我们也可以在列表中传递它
现在我们可以传递no作为no函数。
所以我们已经看到了如何将函数视为
parameters to other functions and these function
parameters are really treated as tight.只是

English: 
type to get around this, we can make use of
the invoke method on that functional type
and then we can make use of the safe call
operator and now, but updating this to do
a safe invoke call on the predicate function.
We can handle this rather not the predicate
is no calling invoke will invoke the function
just as it would any other indication of a
function. So now down here nothing has changed
and how we can call print filtered strings.
However, we could also pass it in list and
now we could pass in no as a no function.
So we've seen how we can treat functions as
parameters to other functions and these function
parameters are really treated as tight. Just

English: 
the same as let's say integer or string. Caitlyn
has this idea of functional types. It's a
first-class part of the language. This means
that we could define a variable of a functional
type and then pass that variable in any time.
We needed a function parameter that matched
that function signature. So an example of
this might be something like vow credit kit
and then we will define our function type
to match that of our print filtered strings
function.
So in this case it'll take a string and return
bullion and now we'll define our function
the same way that we were doing it before.
By saying if the string starts with aJ , go
ahead and return true. Now instead of invoking
print filters, strings with a landed pass
to it, we can pass in our predicate variable
directly. And now if we run this, we'll see

Chinese: 
就像让我们说整数或字符串一样。 Caitlyn
has this idea of functional types.它是
语言的一流部分。 This means
that we could define a variable of a functional
键入然后随时传递该变量。
我们需要一个匹配的函数参数
那个功能签名。 So an example of
this might be something like vow credit kit
and then we will define our function type
to match that of our print filtered strings
功能。
So in this case it'll take a string and return
bullion and now we'll define our function
就像我们之前做的那样。
通过说明字符串是否以aJ开头，去吧
提前并返回true。 Now instead of invoking
print filters, strings with a landed pass
to it, we can pass in our predicate variable
直。现在如果我们运行这个，我们会看到

English: 
the same output as we would before. So this
allows us to store function as variables.
This can be really useful for things like
optional input handling. For example, maybe
you have a view on some screen and you want
to be able to specify a ClickList center for
that view. You could define that as a Lambda
property on some class and allow client code
to set that ClickList center as needed. As
we mentioned before, higher order functions
include functions which take other functions
as parameters, as well as functions that return
other functions.
So let's define a function called get print
predicate and it'll take no parameters, but
we defined its return type as a function which
takes a string and returns a bullion. And

Chinese: 
与我们之前相同的输出。所以这
allows us to store function as variables.
This can be really useful for things like
optional input handling.例如，也许吧
you have a view on some screen and you want
to be able to specify a ClickList center for
那个观点。 You could define that as a Lambda
property on some class and allow client code
根据需要设置ClickList中心。如
we mentioned before, higher order functions
include functions which take other functions
as parameters, as well as functions that return
其他功能。
So let's define a function called get print
predicate and it'll take no parameters, but
we defined its return type as a function which
takes a string and returns a bullion.和

English: 
now we can return that value by saying return.
And then we could pass a Lambda and say it.
That starts with J. So we're passing essentially
the same type of Lambda that we've been using
in these other examples. But now we've wrapped
it in this other function and so now and so
then passing predicate directly or instead
of defining a new Lambda as our function parameter,
we could instead call get print predicate
as a function on its own, which will then
return a function which then can be used as
the predicate for print filtered strings.
And if we run this once again, we'll see that
our output hasn't changed though. So higher
order functions can work as both inputs and
outputs and Kotlin allows you to define properties
with functional types.

Chinese: 
现在我们可以通过说回报来回报这个价值。
然后我们可以传递Lambda并说出来。
That starts with J. So we're passing essentially
the same type of Lambda that we've been using
在这些其他例子中。 But now we've wrapped
it in this other function and so now and so
then passing predicate directly or instead
of defining a new Lambda as our function parameter,
we could instead call get print predicate
as a function on its own, which will then
return a function which then can be used as
the predicate for print filtered strings.
And if we run this once again, we'll see that
our output hasn't changed though.那么高
order functions can work as both inputs and
outputs and Kotlin allows you to define properties
功能类型。

English: 
So through this function's really become a
very powerful and first-class part of the
language that can start to replace a lot of
other instances. For example, you might find
yourself relying more heavily on functions
to define things like event or a ClickList
centers rather than defining concrete interfaces
for those same types of functionality. Now
this was recently mentioned. Much of the Kotlin
standard library is built around higher order
functions and especially a higher order functions
defined with generic types. So if we look
at the implementation of four each, well notice
that this is actually an extension function
as well as a higher order function. So for
each works on generic Iterable type and takes
in a function parameter that takes in that
generic type and returns unit. So this essentially

Chinese: 
So through this function's really become a
very powerful and first-class part of the
language that can start to replace a lot of
other instances.例如，您可能会发现
yourself relying more heavily on functions
to define things like event or a ClickList
centers rather than defining concrete interfaces
for those same types of functionality.现在
这是最近提到的。 Much of the Kotlin
standard library is built around higher order
functions and especially a higher order functions
defined with generic types.所以，如果我们看
at the implementation of four each, well notice
that this is actually an extension function
以及更高阶的功能。因此对于
each works on generic Iterable type and takes
in a function parameter that takes in that
generic type and returns unit.所以这基本上

English: 
allows us to iterate over each element in
the collection and then call that action on
it and it doesn't have to return anything.
And similarly for each index takes in a single
function parameter as well. But this one takes
in an event to represent the index as well
as the generic type. This allows us to iterate
over each element in the collection while
incrementing a counter and then passing that
counter into the function parameter as the
index. The power of generic types, extension
functions and higher order functions allows
us to write single implementations of these
methods and then reuse them over any type
that we can think of. Now this is very powerful
and can allow us to write much more functional
code without having to redefine these methods
and functions for all of our different types.
So let's take a look at example of how we

Chinese: 
allows us to iterate over each element in
the collection and then call that action on
它并没有返回任何东西。
And similarly for each index takes in a single
function parameter as well.但是这个需要
in an event to represent the index as well
as the generic type.这允许我们迭代
over each element in the collection while
incrementing a counter and then passing that
counter into the function parameter as the
index.泛型类型的力量，扩展
functions and higher order functions allows
us to write single implementations of these
methods and then reuse them over any type
that we can think of.现在这非常强大
and can allow us to write much more functional
code without having to redefine these methods
和我们所有不同类型的功能。
那么让我们来看看我们如何做的例子

Chinese: 
can combine some of these different functional
operators to perform complex operations with
很少的代码。 We'll come into this new
main function here and we'll start off by
定义字符串列表。
再来一次。 Now let's look at some ways in
which we can chain these functional operators
一起做更多有趣的事情。所以
as we've seen before, we can do a simple for
each to iterate over each item in this collection
and print it out.如果我们运行它，我们会
notice that we see all of the programming
language printed out to the console.怎么办
if we wanted to print out only the strings
that start with J plus similar to the functions
we were working with before, we could do that
by making use of a filter operation.所以我们
有很多选择可供选择。在这
case, we will just choose a generic filter

English: 
can combine some of these different functional
operators to perform complex operations with
very little code. We'll come into this new
main function here and we'll start off by
defining a list of strings.
Once again. Now let's look at some ways in
which we can chain these functional operators
together to do more interesting things. So
as we've seen before, we can do a simple for
each to iterate over each item in this collection
and print it out. And if we run it, we'll
notice that we see all of the programming
language printed out to the console. Now what
if we wanted to print out only the strings
that start with J plus similar to the functions
we were working with before, we could do that
by making use of a filter operation. So we
have a lot of options to choose from. In this
case, we will just choose a generic filter

Chinese: 
and then we will use a predicate which says
it starts with J and now if we run this was
he, he had only Java and Java script printed
出。现在，如果我们的收藏包括在内
有些没有价值？
So as soon as we add, no, we see now here
in our filter operation, it's warning us that
Hey, this value might be no, you need to add
a safe call weld in Kotlin.我们经常
don't want to work with no, we want to try
and hide no as much as possible.所以我们
could make use of another functional operator
called filter not know.这是做什么的
立即过滤掉任何没有值的人。
所以在功能上过去的一切
连锁店将保证不会。 No. So
as soon as we added filter, not know, we no

English: 
and then we will use a predicate which says
it starts with J and now if we run this was
he, he had only Java and Java script printed
out. Now, what if our collection included
some no values?
So as soon as we add, no, we see now here
in our filter operation, it's warning us that
Hey, this value might be no, you need to add
a safe call weld in Kotlin. Oftentimes we
don't want to work with no, we want to try
and hide no as much as possible. And so we
could make use of another functional operator
called filter not know. What this does is
immediately filter out any no values up front.
So everything past that in the functional
chain will be guaranteed to be not. No. So
as soon as we added filter, not know, we no

English: 
longer had to deal with a possible no string.
And if we run this once again, we'll see only
Java and JavaScript printed out.
Now what if we wanted to change the type of
this? Let's say we wanted to convert this
from a string to an integer, which represents
the length of that input string. We could
do this type of transformation using a map
function. The map function will take in whatever
the previous type is in this case string,
but it'll allow us to return any other type
we want. So in this case, we might define
our map function as simply returning the length
of the string. As soon as we've done that.
Now below that in the for each, the type has
changed from string to end. And now if we
print this out, we'll see four and 10 printed
out for representing the four characters in
Java and 10 representing the 10 characters

Chinese: 
更长时间不得不处理可能没有字符串。
如果我们再次运行这个，我们只会看到
打印出Java和JavaScript。
Now what if we wanted to change the type of
这个？假设我们想转换它
from a string to an integer, which represents
the length of that input string.我们可以
do this type of transformation using a map
功能。地图功能将采取任何措施
the previous type is in this case string,
but it'll allow us to return any other type
我们想要。 So in this case, we might define
our map function as simply returning the length
的字符串。一旦我们这样做了。
现在低于每个类型，类型有
从字符串更改为结束。 And now if we
print this out, we'll see four and 10 printed
out for representing the four characters in
Java and 10 representing the 10 characters

English: 
in Java script. Now let's remove this mapping
and let's remove the filter. And instead,
let's imagine that we want to take only a
certain number of items from this collection.
So we can do that by using the take function
and passing in. Let's say three. What that'll
do is we'll take the first three items from
that collection and then we'll be printing
out each of those three names. So you see
in this case we're getting Kotlin, Java and
C plus plus. Alternatively, if we didn't want
to take the first three elements in the collection,
we could use take last today, the last three.
So in this case we see Java C plus plus and
Java script and it has skipped over Kotlin
since that was not one of the last three elements.
We can also do other transformations such
as associating the input values with some

Chinese: 
在Java脚本中。 Now let's remove this mapping
and let's remove the filter.相反，
let's imagine that we want to take only a
certain number of items from this collection.
So we can do that by using the take function
and passing in. Let's say three.那是什么
do is we'll take the first three items from
that collection and then we'll be printing
这三个名字中的每一个。 So you see
in this case we're getting Kotlin, Java and
C plus plus。 Alternatively, if we didn't want
to take the first three elements in the collection,
我们可以使用今天，最后三个。
所以在这种情况下我们看到Java C plus plus和
Java script and it has skipped over Kotlin
since that was not one of the last three elements.
We can also do other transformations such
as associating the input values with some

English: 
other value to return a map. So let's create
a map that essentially maps the string to
the number of characters in that string. So
to do that we could say associate, and then
in this case we could say it to it dot length.
And so now in our, for each function, instead
of iterating over strings, we're iterating
over map entries of string and event. So in
this case we can now use a template string
and say it got value comma it dot key.

Chinese: 
返回地图的其他值。 So let's create
a map that essentially maps the string to
该字符串中的字符数。所以
to do that we could say associate, and then
在这种情况下，我们可以说它的点长度。
现在，在我们的每个功能中，相反
of iterating over strings, we're iterating
over map entries of string and event.所以
this case we can now use a template string
and say it got value comma it dot key.

Chinese: 
And if we print this out, we'll see the length
comma followed by the name.这样做
really easy to map all of the input strings
to some other value and then iterate over
那张地图。 Now, what if we didn't want to iterate
over the map but instead just wanted to hold
在变量中？ Well, instead of
using a fork each at the end, we could assign
这是一个像这样的变量。 The continent
standard library also provides a variety of
functions to help us pull out individual elements
from a collection to demonstrate that that's
创建了一个名为language的变量。然后
we're going to perform different operations
on our list to grab a single language string
from our list.所以我们可以在一个数字中做到这一点
方式We could say list dot first and if
we print this out, we'll expect to see Kotlin

English: 
And if we print this out, we'll see the length
comma followed by the name. This makes it
really easy to map all of the input strings
to some other value and then iterate over
that map. Now, what if we didn't want to iterate
over the map but instead just wanted to hold
on to that in a variable? Well, instead of
using a fork each at the end, we could assign
this to a variable just like this. The continent
standard library also provides a variety of
functions to help us pull out individual elements
from a collection to demonstrate that that's
created a variable called language. And then
we're going to perform different operations
on our list to grab a single language string
from our list. So we could do that in a number
of ways. We could say list dot first and if
we print this out, we'll expect to see Kotlin

Chinese: 
因为这是列表中的第一种语言。
Alternatively, we could say we'll start last
and in this case you'll see that it's actually
打印出来。 No, since [inaudible] was the
last value in that list.现在，如果我们没有
want to retrieve a null value from our list
and instead wanted the Alaskan non-male value,
once again, we could add the filter, not no
function, which we used previously.现在
if we rerun this, we'll see Java script printed
out instead, since this is the last non no
值。 Now what if we wanted to find a specific
item in the list?假设我们想要使用
the find function and in our predicate we'll
say it got starts with and we'll pass in Java

English: 
as that is the first language in the list.
Alternatively, we could say we'll start last
and in this case you'll see that it's actually
printing out. No, since [inaudible] was the
last value in that list. Now, if we didn't
want to retrieve a null value from our list
and instead wanted the Alaskan non-male value,
once again, we could add the filter, not no
function, which we used previously. And now
if we rerun this, we'll see Java script printed
out instead, since this is the last non no
value. Now what if we wanted to find a specific
item in the list? Let's say we wanted to use
the find function and in our predicate we'll
say it got starts with and we'll pass in Java

Chinese: 
作为一条街。 So this is going to find the
first value in this list that starts with
Java的。 So in this case it actually returns
us Java and alternatively we could use find
last to find the last element in the collection
that matches this predicate, in which case
它将返回JavaScript。
Now what happens if we are searching for a
string which doesn't match our predicate?
We can test that by looking for a string which
starts with food.如果我们再运行它，我们就会
看不到它打印到控制台。这是
because there is no matching string.如此精细。
最后会回来。 No. And then the
print line statement, we'll print out.没有
如果它有一个空值。 Well what if we didn't
want to work with no?如果我们想要的话怎么办？
使用空字符串作为占位符？
好吧，Kotlin中的字符串有一个很有用的功能

English: 
as a street. So this is going to find the
first value in this list that starts with
Java. So in this case it actually returns
us Java and alternatively we could use find
last to find the last element in the collection
that matches this predicate, in which case
it's going to return JavaScript.
Now what happens if we are searching for a
string which doesn't match our predicate?
We can test that by looking for a string which
starts with food. If we then run this, we'll
see no print it out to the console. This is
because there is no matching string. So fine.
Last is going to return. No. And then the
print line statement, we'll print out. No
if it has a null value. Well what if we didn't
want to work with no? What if instead we wanted
to use an empty string as the placeholder?
Well, strings in Kotlin have a useful function

English: 
called or empty. So we can actually chain
that directly off of find last here and call
or empty. So at this will do is return either
a nano string or a static empty string. So
now if we run this once again, instead of
no, we're just seeing empty, we're not printing
anything out.
So this is one way in which you could default
your collections or your strings to an empty
value as opposed to a no value. And this is
something you might want to consider doing
more and more of in Kotlin as you start to
move away from relying on null. So as we've
seen, Caitlyn has first-class support for
functions including functional types and higher
order functions, and the Kotlin standard library
builds upon those tools and provides a rich
set of functional operators for us to use.
This allows us to build powerful functional

Chinese: 
叫或空。 So we can actually chain
that directly off of find last here and call
或空的。 So at this will do is return either
a nano string or a static empty string.所以
now if we run this once again, instead of
no, we're just seeing empty, we're not printing
什么都没有。
So this is one way in which you could default
your collections or your strings to an empty
价值而不是无价值。 And this is
something you might want to consider doing
more and more of in Kotlin as you start to
move away from relying on null.就像我们一样
seen, Caitlyn has first-class support for
functions including functional types and higher
order functions, and the Kotlin standard library
builds upon those tools and provides a rich
我们使用的一组功能操作符。
这使我们能够构建强大的功能

English: 
chains to transform our data and make complex
workflows much simpler. All right, that's
it for this tutorial. You now have a good
understanding of the fundamentals of Kotlin
and how to work with it, and you're now ready
to start taking that knowledge and applying
it to other domains. Until next time, devs.

Chinese: 
chains to transform our data and make complex
workflows much simpler.好的，就是这样
它适用于本教程。 You now have a good
understanding of the fundamentals of Kotlin
and how to work with it, and you're now ready
to start taking that knowledge and applying
它到其他领域。直到下一次，开发者。
