Skip to content

Commit 620d047

Browse files
committed
提交协程等三篇文章。
1 parent e2163b4 commit 620d047

13 files changed

+795
-6
lines changed

articles/2017.1.23/cover.jpg

69.7 KB
Loading
110 KB
Loading

articles/2017.1.30/coroutine_lua.png

110 KB
Loading

articles/2017.1.30/cr0.png

245 KB
Loading

articles/2017.1.30/cr1.png

91 KB
Loading

articles/2017.1.30/cr2.png

131 KB
Loading

articles/2017.1.30/mdhere.gif

100 KB
Loading
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# 勘误:15 Kotlin 与 Java 共存 (2)
2+
3+
在过去推送过的第15期视频中,涉及到一个泛型对比的点,当时文中提到“对于循环引用泛型参数的情况,Kotlin 无法实现”的结论是有问题的。感谢 @zhangdatou 指正,对应部分的内容修改如下:
4+
5+
## 3 泛型
6+
7+
整体上来讲,Kotlin 的泛型与 Java 的没什么大的差别,Java 的 ? 在 Kotlin 中变成了 *,毕竟 ? 在 Kotlin 当中用处大着呢。另外,Java 泛型的上限下限的表示法在 Kotlin 当中变成了 out 和 in。
8+
9+
不过,由于 Java 1.5 之前并没有泛型的概念,为了兼容旧版本,1.5 之后的 Java 仍然允许下面的写法存在:
10+
11+
```java
12+
List list = new ArrayList();
13+
list.add("Hello");
14+
list.add(1);
15+
for (Object o : list) {
16+
System.out.println(o);
17+
}
18+
```
19+
而对应的,在 Kotlin 当中要用 List<*> 来表示 Java 中的 List —— 这本身没什么问题。那么我们现在再看一段代码:
20+
21+
```java
22+
public abstract class View<P extends Presenter>{
23+
protected P presenter;
24+
}
25+
26+
public abstract class Presenter<V extends View>{
27+
protected V view;
28+
}
29+
```
30+
这个其实是现在比较流行的 MVP 设计模式的一个简单的接口,我希望通过泛型来绑定 V-P,并且我可以通过泛型参数在运行时直接反射实例化一个 presenter 完成 V-P 的实例注入,这在 Java 当中是没有问题的。
31+
32+
那么在 Kotlin 当中呢? 因为我们知道 View 和 Presenter 都有泛型参数的,所以我们在 Kotlin 当中就要这么写:
33+
34+
```kotlin
35+
abstract class View<P : Presenter<out View<out Presenter<out View<...>>{
36+
protected abstract val presenter: P
37+
}
38+
39+
abstract class Presenter<out V : View<out Presenter<out View<...>>>>{
40+
protected abstract val view: V
41+
}
42+
```
43+
一直写下去,最终陷入了死循环。编译器给出的解释是:
44+
45+
>This type parameter violates the Finite Bound Restriction.
46+
47+
@zhangdatou 给我发邮件之前,我曾一直对此耿耿于怀,Kotlin 这么优秀的语言怎么还会有做不到的事情呢。原来不是做不到,而是我没有想到:
48+
49+
```kotlin
50+
abstract class View<out P: Presenter<View<P>>>
51+
abstract class Presenter<out V: View<Presenter<V>>>
52+
53+
class MyView: View<MyPresenter>()
54+
class MyPresenter: Presenter<MyView>()
55+
```
56+
实际上我们需要 View 的泛型参数 P 只要是 Presenter 的子类即可,并且要求这个泛型参数 P 本身对应的泛型参数也需要是 View 的子类,而这个 View 其实就是最初的那个 View,那么这个 View 的泛型参数当然就是 P 了。有点儿绕,但这么写出来明显感觉比 Java 安全靠谱多了。
57+
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# 如何优雅的在微信公众号中编辑代码
2+
3+
这篇文章严格意义上是写给有公众号且公众号文章需要贴代码的朋友们看的。
4+
5+
## 1 公众号编辑器真难用
6+
7+
自从入坑公众号以来,被公众号的这个编辑器简直折磨死了。我发的文章基本上是少不了贴代码的,可是每次贴上去的代码总是被公众号的编辑器无厘头的给我过滤掉换行符,简直气死人。
8+
9+
例如我编辑得好好的代码,
10+
11+
```java
12+
Person person = new Person("benny", 27);
13+
System.out.println(person.getName() + " is " + person.age); //benny is 27
14+
person.setName("andy");
15+
person.age = 26;
16+
System.out.println(person.getName() + " is " + person.age); //andy is 26
17+
```
18+
19+
贴上去就成了这样:
20+
21+
```java
22+
Person person = new Person("benny", 27);System.out.println(person.getName() + " is " + person.age); //benny is 27person.setName("andy");person.age = 26;System.out.println(person.getName() + " is " + person.age); //andy is 26
23+
```
24+
25+
每次一段代码一段代码的敲回车,简直敲到手抽筋。醉了。
26+
27+
这还不算,这个格式的代码发到手机上,还不能水平滚动,各种任性的折行,让本来清秀的代码看起来真是一坨一坨的。
28+
29+
## 2 分析下原因
30+
31+
查了一下,不少同行都在因为这个而感到苦恼,大家分析得出的结论是微信公众号的编辑器会对我们贴上去的内容进行处理,而处理的过程中又会对一些换行符进行过滤,导致本来排好的代码乱成一团。
32+
33+
## 3 几种常见的贴代码的方法
34+
35+
### 3.1 贴图法
36+
37+
对于这种情况,最直接的方法自然是用工具渲染好,然后截图贴到公众号的编辑器里面。也可以写一个工具把代码自动绘成图片。
38+
39+
* 优点:简单直接,在找到更好的办法之前,我之前的几篇文章都是这么处理的。
40+
* 缺点:操作繁琐,除了生成图片或者截图,还要手动贴到公众号编辑器中,截图时对于代码的文字清晰度控制也不太容易,贴到编辑器之后,还会被压缩,导致代码不容易被看清楚。当然,另一个更大的硬伤就是读者阅读的时候会耗费比较多的流量,如果网速不好还会加载不出来。
41+
42+
### 3.2 Markdown Here
43+
44+
很多朋友都提到 Markdown Here,这是一个非常棒的 Chrome 插件,大家可以搜索并添加它,安装之后可以在 Options 当中选择自己喜欢的主题,之后只要在选中编辑框,贴入 Markdown 源码,再点击插件的按钮即可。
45+
46+
![](mdhere.gif)
47+
48+
不过。。这个插件同样不能幸免于换行符的过滤,如果我们在微信公众号编辑器当中贴入 md 源码,按照上述操作渲染出漂亮的格式,保存之后预览,你就会发现这个办法其实并不怎么好用,或者说基本上不能用。
49+
50+
* 优点:这插件真的很棒。
51+
* 缺点:因为渲染后的格式还是会惨遭微信公众号的编辑器的毒手,也就是说,你得自己手动处理一下换行的问题。
52+
53+
### 3.3 渲染好的格式直接贴
54+
55+
我们前面说,可以先把 md 源码渲染好,然后直接复制粘贴到公众号的编辑器当中,结果其实与 Markdown Here 的效果完全一样。说到底是换行符被过滤的问题。
56+
57+
我一直用的 md 工具是 MacDown,可以直接先用它编辑好文章,然后复制渲染结果贴到微信公众号当中,自行处理一下换行的问题即可。
58+
59+
* 优点:本地编辑,方便快捷。
60+
* 缺点:一样,还是换行符的问题。
61+
62+
### 3.4 其他什么编辑器
63+
64+
当你在搜索引擎里面搜索这个问题的时候,大多数回答可能是推荐你用一些第三方的编辑器,比如 什么 135 编辑器之类的,这些编辑器对于不写代码的朋友来说,真的挺好用的,里面提供了各式各样的模板,大家只要把文字准备好,一套用就立马狂拽酷炫吊炸天。
65+
66+
可是,它们并不是为我们这些码农准备的啊,你想想公众号绝大多数的运营者都是编辑,而不是程序员,他们根本不需要关心什么是代码,更不需要关心怎么把代码排版好(我相信微信公众号编辑器的开发小伙伴大概也是这么想的吧,这么久了这编辑器还是这鬼样子)。
67+
68+
第三方编辑器很多,不过,当你一个一个去试的时候,你会发现这条路根本不通!!
69+
70+
* 优点:适合编辑各种花哨的文字和图片。
71+
* 缺点:不支持代码的格式。
72+
73+
## 4 目前最优雅的方案诞生记
74+
75+
说实在的这个方案没有很高端。我们的痛点其实就是想个办法不让微信公众号编辑器对贴到里面的代码进行换行符的过滤。
76+
77+
有朋友提出把渲染后的结果每行都用 <br> 替换 \n,这样过滤时,换行自然就不会被干掉了。
78+
79+
```html
80+
<code class="hljs language-java"
81+
style="...">Person person = <span class="hljs-keyword" style="color: rgb(170, 13, 145);">new</span> Person(<span
82+
class="hljs-string"
83+
style="color: rgb(196, 26, 22);">"benny"</span>,
84+
<span class="hljs-number" style="color: rgb(28, 0, 207);">27</span>);
85+
System.out.println(person.getName() + <span class="hljs-string" style="color: rgb(196, 26, 22);">" is "</span> +
86+
person.age); <span class="hljs-comment" style="color: rgb(0, 106, 0);">//benny is 27</span>
87+
person.setName(<span class="hljs-string" style="color: rgb(196, 26, 22);">"andy"</span>);
88+
person.age = <span class="hljs-number" style="color: rgb(28, 0, 207);">26</span>;
89+
System.out.println(person.getName() + <span class="hljs-string" style="color: rgb(196, 26, 22);">" is "</span> +
90+
person.age); <span class="hljs-comment" style="color: rgb(0, 106, 0);">//andy is 26</span>
91+
</code>
92+
```
93+
94+
这就是 md 渲染后的结果,代码对应于文章开头的例子。我们发现所有的代码被放到 code 这个标签当中,如果我们在其中用 <br> 替换 \n 会发生什么呢?
95+
96+
```java
97+
Person person = new Person("benny", 27);
98+
System.out.println(person.getName() + " is " + person.age); //benny is 27
99+
person.setName("andy");<br>person.age = 26;
100+
System.out.println(person.getName() + " is " + person.age); //andy is 26
101+
```
102+
```<br>``` 被直接显示出来了。根本不能用来换行。所以直接从结果入手好像没那么简单。那怎么办,我们干脆修改渲染方式吗?针对每行,用 ```<p />``` 标签包起来不就可以换行了吗?
103+
104+
想法挺好啊。想到这里我就开始准备去修改 Markdown Here 的源码了。。。可,尼玛,我不是搞前端的,一片一片的 js 代码我该修改哪里呢?这下可尴尬了。
105+
106+
此路通,可能成本还是有点儿高了。于是我又回到原点,思考如何欺骗微信公众号编辑器那个换行符不能被过滤的问题。怎么骗呢?关键是,公众号的编辑器通过识别怎样的 pattern 来过滤换行符呢?如果我找到这个 pattern,然后把它破坏掉,不就可以了么?
107+
108+
经过一番尝试发现:
109+
110+
* 每一行代码的前后各加一个空格,那么正常有内容的行末换行符就不会被过滤
111+
* 空行替换成“英文空格+中文空格+英文空格”,这样在微信公众号编辑器看起来似乎不是空行,不过在我们看来其实是空行
112+
113+
于是我动手写了一个简单的 python 脚本,那么后续我只要用 MacDown 编辑好我的文章,再用下面这个脚本自动为所有的代码加上空格、替换空行,那么我再把渲染好的文章贴到公众号的话,大功就告成了。
114+
115+
附上非常简单的脚本代码:
116+
117+
```py
118+
#!/usr/local/bin/python
119+
# encoding=utf-8
120+
 
121+
# 微信公众号编辑器对代码支持的不好, 我们在贴代码之前需要在代码前后各加一个空格
122+
# 并对空行做一下处理,主要随便搞几个空格和制表符
123+
# 这样做可以防止公众号的编辑器过滤空行和换行符
124+
 
125+
import sys, re
126+
 
127+
# 匹配 md 的代码起始块, 我习惯用 ```java 这样的形式, 也可以根据需求进行修改
128+
CODE_PATTERN_START = r"^\s*```\s*\w*$"
129+
# 匹配代码块结束, ```
130+
CODE_PATTERN_END = r"^\s*```\s*$"
131+
if len(sys.argv) < 2:
132+
print "参数不正确."
133+
exit()
134+
 
135+
inputFile = open(sys.argv[1])
136+
output = []
137+
while True:
138+
line = inputFile.readline()
139+
if line:
140+
if re.match(CODE_PATTERN_START, line):
141+
output.append(line)
142+
while True:
143+
line = inputFile.readline()
144+
if re.match(CODE_PATTERN_END, line):
145+
output.append(line)
146+
break
147+
if line.strip():
148+
# 代码行前后各加一个空格
149+
line = " " + line
150+
line = line.replace("\n", " \n")
151+
print line
152+
else:
153+
print "空行"
154+
# 替换空行,下面的空格中有一个是中文空格
155+
line = "   \n"
156+
output.append(line)
157+
else:
158+
output.append(line)
159+
else:
160+
break
161+
inputFile.close()
162+
 
163+
outputFile = open(sys.argv[1], 'w+')
164+
outputFile.writelines(output)
165+
outputFile.close()
166+
```
167+
168+
## 5 小结
169+
170+
这种方法应该算不上一个最终的方案(最终方案应该是公众号编辑器的开发该考虑的事儿),但它成本比较低,输出效果也比较不错,希望能给大家带来帮助。

0 commit comments

Comments
 (0)