最后
总之啊,家里没矿的同学们,如果你们想以后的日子过得好一些,多想想你们的业余时间怎么安排吧;
技术方面的提升肯定是重中之重,但是技术外的一些“软实力”也不能完全忽视,很多时候升职确实是因为你的技术足够强,但也与你的“软实力”密切相关
在这我也分享一份大佬自己收录整理的 Android学习PDF+架构视频+面试文档+源码笔记 ,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅并给下属员工学习的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。
总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
相信自己,没有做不到的,只有想不到的
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
尽管这是一个非常简单的例子,但仍然不想从头编写这个函数。首先,这里可能会犯一个错误,比如忘记括号。第二,我们已经有了一个加 10 的函数 add10 和一个乘以 5 的函数 mult5 ,所以这里我们就在写已经重复的代码了。
使用函数 add10,mult5 来重构 mult5AfterAdd10 :
var mult5AfterAdd10 = value => mult5(add10(value));
我们只是使用现有的函数来创建 mult5AfterAdd10,但是还有更好的方法。
在数学中, f ∘ g 是函数组合,叫作“f 由 g 组合”,或者更常见的是 “f after g”。 因此 (f ∘ g)(x) 等效于f(g(x)) 表示调用 g 之后调用 f。
在我们的例子中,我们有 mult5 ∘ add10 或 “add10 after mult5”,因此我们的函数的名称叫做 mult5AfterAdd10。由于Javascript本身不做函数组合,看看 Elm 是怎么写的:
add10 value =
value + 10
mult5 value =
value * 5
mult5AfterAdd10 value =
(mult5 << add10) value
在 Elm 中 << 表示使用组合函数,在上例中 value 传给函数 add10 然后将其结果传递给 mult5。还可以这样组合任意多个函数:
f x =
(g << h << s << r << t) x
这里 x 传递给函数 t,函数 t 的结果传递给 r,函数 t 的结果传递给 s,以此类推。在Javascript中做类似的事情,它看起来会像 g(h(s(r(t(x))))),一个括号噩梦。
Point-Free Notation
**Point-Free Notation**就是在编写函数时不需要指定参数的编程风格。一开始,这风格看起来有点奇怪,但是随着不断深入,你会逐渐喜欢这种简洁的方式。
在 multi5AfterAdd10 中,你会注意到 value 被指定了两次。一次在参数列表,另一次是在它被使用时。
// 这个函数需要一个参数
mult5AfterAdd10 value =
(mult5 << add10) value
但是这个参数不是必须的,因为该函数组合的最右边一个函数也就是 add10 期望相同的参数。下面的 point-free 版本是等效的:
// 这也是一个需要1个参数的函数
mult5AfterAdd10 =
(mult5 << add10)
使用 point-free 版本有很多好处。
-
首先,我们不需要指定冗余的参数。由于不必指定参数,所以也就不必考虑为它们命名。
-
由于更简短使得更容易阅读。本例比较简单,想象一下如果一个函数有多个参数的情况。
天堂里的烦恼
到目前为止,我们已经了解了组合函数如何工作以及如何通过 point-free 风格使函数简洁、清晰、灵活。
现在,我们尝试将这些知识应用到一个稍微不同的场景。想象一下我使用 add 来替换 add10:
add x y =
x + y
mult5 value =
value * 5
现在如何使用这两个函数来组合函数 mult5After10 呢?
我们可能会这样写:
-- 这是错误的!!!
mult5AfterAdd10 =
(mult5 << add) 10
但这行不通。为什么? 因为 add 需要两个参数。
这在 Elm 中并不明显,请尝试用Javascript编写:
var mult5AfterAdd10 = mult5(add(10)); // 这个行不通
这段代码是错误的,但是为什么?
因为这里 add 函数只能获取到两个参数(它的函数定义中指定了两个参数)中的一个(实际只传递了一个参数),所以它会将一个错误的结果传递给 mult5。这最终会产生一个错误的结果。
事实上,在 Elm 中,编译器甚至不允许你编写这种格式错误的代码(这是 Elm 的优点之一)。
我们再试一次:
var mult5AfterAdd10 = y => mult5(add(10, y)); // not point-free
这个不是point-free风格但是我觉得还行。但是现在我不再仅仅组合函数。我在写一个新函数。同样如果这个函数更复杂,例如,我想使用一些其他的东西来组合**mult5AfterAdd10**,我真的会遇到麻烦。
由于我们不能将这个两个函数对接将会出现函数组合的作用受限。这太糟糕了,因为函数组合是如此强大。
如果我们能提前给add函数一个参数然后在调用 mult5AfterAdd10 时得到第二个参数那就更好了。这种转化我们叫做 柯里化。
柯里化 (Currying)
Currying 又称部分求值。一个 Currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值
上例我们在组合函数 mult5和 add(in) 时遇到问题的是,mult5 使用一个参数,add 使用两个参数。我们可以通过限制所有函数只取一个参数来轻松地解决这个问题。我只需编写一个使用两个参数但每次只接受一个参数的add函数,函数柯里化就是帮我们这种工作的。
柯里化函数一次只接受一个参数。
我们先赋值 add 的第1个参数,然后再组合上 mult5,得到 mult5AfterAdd10 函数。当 mult5AfterAdd10 函数被调用的时候,add 得到了它的第 2 个参数。
JavaScript 实现方式如下:
var add = x => y => x + y
此时的 add 函数先后分两次得到第 1 个和第 2 个参数。具体地说,add函数接受单参x,返回一个也接受单参 **y**的函数,这个函数最终返回 x+y 的结果。
现在可以利用这个 add 函数来实现一个可行的 mult5AfterAdd10* :
var compose = (f, g) => x => f(g(x));
var mult5AfterAdd10 = compose(mult5, add(10));
compose 有两个参数 f 和 g,然后返回一个函数,该函数有一个参数 x,并传给函数 f,当函数被调用时,先调用函数 g,返回的结果作为函数 **f**的参数。
总结一下,我们到底做了什么?我们就是将简单常见的**add**函数转化成了柯里化函数,这样add函数就变得更加自由灵活了。我们先将第1个参数10输入,而当mult5AfterAdd10函数被调用的时候,最后1个参数才有了确定的值。
柯里化与重构(Curring and Refactoring)
函数柯里化允许和鼓励你分隔复杂功能变成更小更容易分析的部分。这些小的逻辑单元显然是更容易理解和测试的,然后你的应用就会变成干净而整洁的组合,由一些小单元组成的组合。
例如,我们有以下两个函数,它们分别将输入字符串用单花括号和双花括号包裹起来:
bracketed = function (str) {
retrun "{" + str + "}"
}
doubleBracketed = function (str) {
retrun "{{" + str + "}}"
}
调用方式如下:
var bracketedJoe = bracketed('小智')
var doubleBracketedJoe = doubleBracketed('小智')
可以将 bracket 和 doubleBracket 转化为更变通的函数:
generalBracket = function( prefix , str ,suffix ) {
retrun prefix ++ str ++ suffix
}
但每次我们调用 generalBracket 函数的时候,都得这么传参:
var bracketedJoe = generalBracket("{", "小智", "}")
var doubleBracketedJoe = generalBracket("{{", "小智", "}}")
之前参数只需要输入1个,但定义了2个独立的函数;现在函数统一了,每次却需要传入3个参数,这个不是我们想要的,我们真正想要的是两全其美。
因为生成小括号双括号功能但一,重新调整一下 我们将 generalBracket 三个参数中的 prefix,str 各柯里化成一个函数,如下:
generalBracket = function( prefix ) {
return function( suffix ){
return function(str){
return prefix + str + suffix
}
}
}
这样,如果我们要打印单括号或者双括号,如下:
// 生成单括号
var bracketedJoe = generalBracket('{')('}')
bracketedJoe('小智') // {小智}
// 生成双括号
var bracketedJoe = generalBracket('{{')('}}')
bracketedJoe('小智') // {{小智}}
常见的函数式函数(Functional Function)
最后
我这里整理了一份完整的学习思维以及Android开发知识大全PDF。
当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
)(‘}}’)
bracketedJoe(‘小智’) // {{小智}}
常见的函数式函数(Functional Function)
-----------------------------
### 最后
我这里整理了一份完整的学习思维以及Android开发知识大全PDF。
[外链图片转存中...(img-4jDxcf7q-1715896338745)]
当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**