2022-08-20 原《每周读书》系列更名为《枫影夜读》

因着张爱玲这句“张恨水小说中的男主角”,对这男主角究竟是怎样颇为好奇。又想张恨水是比张爱玲的年代要更久远的作家,不自觉便把他同“很无趣的民国小说”绑在了一起。却没想到《秦淮世家》这部小说很出意料之外,写作手法很是新潮,悬念丛生,颇为吸引。
故事讲述了秦淮河上一户“歌女”人家与一个上海富商斗争的事情,男主角是在夫子庙摆书摊的穷书生徐亦进。形式上小说是旧式的章回体写法,手法上却很新潮,一开场就是歌女家的唐大嫂向邻桌“不认识的兄弟”打招呼,牵出“穷书生拾金不昧”之事,进而把这么一位刚正不阿读圣贤书之人,和“养娼妓”的人家联系到了一起,读者不由兴趣盎然:两种对立的人物碰撞到一起,能擦出什么样的火花来?
随后故事又引出有倾城容貌却颇为高傲的歌女唐小春,和“出淤泥而不染”的二小姐唐二春,男主角与二小姐的情意把男主角推进事件的漩涡,再无法抽离。随着故事的发展,男主角与唐家妈间处世哲学的对立,与二小姐的感情纠葛开始产生强烈的化学反应,这时候恶势力出现了,面对绑架与压迫,唐家嫂选择了逆来顺受,而性格激烈的二小姐与正直不屈的男主角则负隅顽抗,全书在与恶势力的终极对决中达到高潮。
在今天看来这个故事可能比较普通,然而作者却妙笔生花,每个章回都埋下一个悬念,牢牢抓住读者的眼球。但是到了小说后期,作者频频切换人物视角(POV),笔墨都着落在次要人物大狗和二春身上,让冲突的紧张感损失不少,一来失却了故事的紧张感,二来主角的戏份减少,让人不免有一种对人物的感情投资没有回报的失落之感。对于小说来说,这种失策是致命的,直接让读者没了一定要读的兴趣。
本是冲着“张恨水小说的男主角”这个印象去的,最后却发现男主角其实并没有什么戏份,连故事末最有象征意义的一把火都不是他点的,令人哭笑不得。故事倒是有些意境,恶势力的贼窝被烧毁之后,原地很快又新建起一栋高楼,原先为了躲开恶势力的唐小春回到秦淮河继续卖唱,太阳照样升起,地球一样转。主角们拼上性命的斗争,不过是秦淮河上一个小水花,淹没在岁月长河之中。
秦淮河上的女人,是离不开秦淮河的。
15.06.04
本文为 www.raywenderlich.com 上的一篇教程,由枫影翻译。
原文地址 http://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift

更新记录:本教程由 Richard Turton 针对 iOS 8, Xcode 6.1 和 Swift 进行了更新。原文由团队成员 Soheil Azarpour 编写。
相信大家都有过这样令人沮丧的经验:在 iOS/Mac 应用里按下一个按钮或者输入一些文字的时候,突然间整个界面就卡住不动了。
在 Mac 上,用户只能盯着那个彩色的球不停地转圈圈,好一会儿才能继续使用你的应用。在 iOS 上,用户则期望应用应该能实时地对自己的触摸动作进行反馈。这些不够流畅的应用看起来笨重而拖沓,一般都是差评如潮。
然而保持应用流畅度却是说起来容易做起来难。一旦你的应用需要执行繁重的任务,事情就会变得复杂起来。要在 Main Run Loop 里同时执行繁重的任务并且进行流畅的响应是不可能的事情。
一个可怜的开发者对此能做点什么呢?答案就是把繁重的任务从主线程挪到另一个并发的线程上。并发意味着你的应用可以同时多个操作流(或者线程)——以此达到界面响应用户输入的同时还能执行其他任务。
NSOperation 和 NSOperationQueue 是在 iOS 上实现并发操作的一种方法。在本教程中,你将会学习如何使用这些类。我们将从一个完全不使用并发的应用开始,这个应用会看起来很迟钝,然后你将对这个应用进行重构,加入并发操作让界面变得流畅起来!
本教程的示例工程主要用于展示一个 TableView,里面是加过滤镜的图片。图片要从网上下载下来,在本地加上滤镜效果,然后在展示在 TableView 里面。
下图是这个应用的模型:

请下载本教程的示例代码:http://cdn5.raywenderlich.com/wp-content/uploads/2014/10/ClassicPhotos-Starter63.zip
注意:所有的图片都来自stock.xchng。部分图片故意拼错名字,用于测试下载失败的情况
编译运行这个工程,然后(最终)你讲看到这个应用里展示了一个图片列表。试试看滚动一下这个列表,是不是菊花一紧?

所有的动作都在 ListViewController.swift 这个类里面,而且多数都写在 tableView(_:cellForRowAtIndexPath:) 方法里。
你会发现有两个操作是特别重的:
此外,应用刚开始还从网上下载了一份图片列表:
所有这些操作都是在主线程做的。由于主线程是用于更新UI,同用户交互的线程,阻塞了主线程就会让整个应用看起来很卡。你可以使用 Xcode 的 gauges view 查看应用的执行参数。

你可以看到 Thread 1 (也就是主线程)的 CPU 占用情况。如果想要查看应用的更多详情,你可以使用 Instruments,不过关于 Instruments 可以用一整篇文章来讲了。
OK,现在是时候进入优化部分了。
开始教程正文之前,这里有几个技术概念需要明确一下:
注意:在 iOS 和 OS X 中,多线程功能是由 POSIX Threads API(或者说 pthread)提供的,属于操作系统的一部分。这是一个比较底层的 API,很容易犯错,而且最糟糕的事这些错误是很难被察觉到的!
Foundation 框架里有一个类叫做 NSThread,相较而言要比底层接口好用多了,但是管理基于 NSThread 的多线程还是相当令人头疼。NSOperation 和 NSOperationQueue 则是更高级的类,提供更加简单的多线程管理接口。
下图中,你可以看到任务,线程和进程三者的关系:

可以看到,一个进程可以包含多个可以执行的线程,一个线程则可以同时执行多个人物。
在上图中,线程 2 执行读文件的操作,同时线程 1 则执行界面的展示工作。这跟 iOS 代码的结构很相似——主线程执行界面相关操作,子线程则负责耗时操作,比如读文件,网络操作等等。
你可能早已听过 Grand Central Dispatch (GCD) 的大名了。GCD 包含了语言特性,运行时库和系统优化,给 iOS 和 OS X 的并发和多核编程提供了一套系统而且强大的接口。想要了解更多关于 GCD 的内容,可以参考我们的文章:Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial。
NSOperation 和 NSOperationQueue 是基于 GCD 之上的。一个通用的规则,苹果建议尽量使用最高级别的抽象接口,只有经过仔细权衡后觉得确实更底层的接口,才往下层走。
下面是一个 NSOperation 和 GCD 的一个简单的比较,便于你选择应该使用哪一种接口:
由于本文的示例中将对 Table View 进行优化,基于提高性能和减少功耗的考虑,你需要在一个图片 cell 被滚动出屏幕外的时候能够取消对这个图片正在执行的操作,所以我们将使用 NSOperation 来做这个优化。即使所有的操作都是在后台线程做的,如果有几十个耗时操作一直在后台队列中无法取消,对性能也是一种打击。
现在是时候完善一下那个没有多线程的应用模型了!如果你仔细观察这个一开始的模型,你会发现有三个地方可以被多线程优化。只要把这三个地方拆解到其他线程,主线程就可以减轻不少压力,提高流畅度。

为了突破应用的性能瓶颈,你将有一个主线程用于实时反馈用户输入,一个子线程专门用来下载图片,还有一个子线程用来对图片添加滤镜效果。在新的模型中,这个应用会从主线程启动,然后先加载一个空的 Table View。与此同时,应用将启动一个子线程用于下载数据源。
一旦数据源下载完,你将通知 Table View 进行 Reload。Reload Table View 是 UI 操作,所以一定要在主线程执行。在这时, Table View 就知道有多少行数据要进行展示,也知道每一行的图片对应的 URL。但是 Table View 还没拿到真正的图片数据!所以这个时候去下载所有图片是不明智的,你只需要看得到的那几张图片就可以了。
这里有什么可以优化的点呢?
一个更好的模型是,只下载显示在屏幕上的那几张图片。所以你的代码首先要问 Table View 要能看到的那些行,然后开始下载的工作。同时,滤镜线程在没有真实图片之前也无法开始工作。所以,在图片还没有下载完之前,滤镜线程不应该被启动。
要让应用看起来更流畅,你的代码应该要能在图片下载完就立刻显示出来。然后再启动滤镜线程,等滤镜加载完毕再更新 UI 显示添加过滤镜的图片。下面这个图片展示了完整的流程:

为了达成这些目标,你首先需要跟踪正在下载、已经下载完的图片,还要知道图片是否已经加过滤镜了。然后你还需要跟踪每一个操作的状态,以便在用户滚动界面时可以取消、暂停或者继续之前的操作。
Okay!现在我们已经准备好开始写代码了!:]
打开示例工程,添加一个新的 Swift 文件,名为:PhotoOperations.swift。添加以下代码:
// This enum contains all the possible states a photo record can be in
enum PhotoRecordState {
case New, Downloaded, Filtered, Failed
}
class PhotoRecord {
let name:String
let url:NSURL
var state = PhotoRecordState.New
var image = UIImage(named: "Placeholder")
init(name:String, url:NSURL) {
self.name = name
self.url = url
}
}
[/sourcecode]
注意:请确保 import UIKit 这句在文件的顶部。默认情况下,Xcode 会帮你引入 Foundation 文件的。
这个简单的类将代表每一个展示在应用里的图片,同时包含图片的状态(初始状态为 .New)。图片默认是一张占位图。
为了追踪每一个操作的状态,你需要另一个类。把下面这个类的定义加到 PhotoOperations.swift 底部:
lazy var filtrationsInProgress = [NSIndexPath:NSOperation]()
lazy var filtrationQueue:NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Image Filtration queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
}
[/sourcecode]
这个类包含了两个 Dictionary,用来追踪 Table View 里每一行的下载和滤镜状态,同时还有两个 Operation Queue 用于图片下载和滤镜操作管理。
所有的值都被声明为 lazy create,也就是说只有等到第一次用到这个值它才会真正被初始化。这也将是应用的性能得到提升。
创建一个 NSOperationQueue 也是挺直观的。给 NSOperationQueue 命名是很有用的,这个名字会在 Instruments 或者 debugger 里面显示出来。出于本文的教学目的,这里最大并发数 maxConcurrentOperationCount 被设为 1,这样你可以清楚地看到这些操作一个接一个地往下走。你也可以改成让队列本身去决定最大并发数,这将更大地提升你的应用性能。
那么队列本身是怎么决定最大并发数的呢?好问题!:]这是由硬件来决定的。默认情况下,NSOperationQueue 会自己计算出对当前平台来说最好的决策,然后启动尽可能多的线程。
试想一下下面这个例子。假设这时候系统出于空闲状态,有很多可用资源,那么这个队列可能会启动大概 8 个并发线程。下一次你启动这个 App 的时候,有可能系统正在处理其他操作,那这个队列可能就只有 2 个并发线程。在这个示例工程里,由于你设置了最大并发数为 1,所以同时只会有一个操作在执行。
注意:你可能觉得奇怪,为什么我们要跟踪所有下载中和等待下载的操作,队列本身有一个 operations 属性可以返回所有操作,为什么不直接用这个就好了?在这个项目中,这么做可能不太高效。因为你必须把 table view 的行数和操作关联起来,这么做意味着你每次都要循环一遍整个数组去查找属于哪一行,使用 Dictionary 把 indexPath 作为 Key 存起来则可以很快地找到对应的操作。
接下来我们要对下载和滤镜操作进行管理了。把下面这些代码加到 PhotoOperations.swift 文件底部:
//2
init(photoRecord: PhotoRecord) {
self.photoRecord = photoRecord
}
//3
override func main() {
//4
if self.cancelled {
return
}
//5
let imageData = NSData(contentsOfURL:self.photoRecord.url)
//6
if self.cancelled {
return
}
//7
if imageData?.length > 0 {
self.photoRecord.image = UIImage(data:imageData!)
self.photoRecord.state = .Downloaded
}
else
{
self.photoRecord.state = .Failed
self.photoRecord.image = UIImage(named: "Failed")
}
}
}
[/sourcecode]
NSOperation 是一个抽象类,是为了继承而设计的。每一个子类代表一个特殊的任务(如前所述)。
上面代码里各行注释的含义如下:
接下来,你需要创建另一个 Operation,用于执行滤镜操作!把下面代码添加到 PhotoOperations.swift 文件里:
init(photoRecord: PhotoRecord) {
self.photoRecord = photoRecord
}
override func main () {
if self.cancelled {
return
}
if self.photoRecord.state != .Downloaded {
return
}
if let filteredImage = self.applySepiaFilter(self.photoRecord.image!) {
self.photoRecord.image = filteredImage
self.photoRecord.state = .Filtered
}
}
}
[/sourcecode]
这个看上去很像下载 Operation,只是用图片添加滤镜(这里用了一个还没实现的函数,所以会有一个编译错误)代替了下载操作。
下面我们给 ImageFiltration 类添加图片滤镜操作的代码:
if self.cancelled {
return nil
}
let context = CIContext(options:nil)
let filter = CIFilter(name:"CISepiaTone")
filter.setValue(inputImage, forKey: kCIInputImageKey)
filter.setValue(0.8, forKey: "inputIntensity")
let outputImage = filter.outputImage
if self.cancelled {
return nil
}
let outImage = context.createCGImage(outputImage, fromRect: outputImage.extent())
let returnImage = UIImage(CGImage: outImage)
return returnImage
}
[/sourcecode]
这里的滤镜实现跟之前 ListViewController 中的实现是一样的,只是搬到了一个 Operation,从而可以在后台执行这个操作。同样的,你还是要经常检查任务是否已经被取消了,最佳实践是在耗时操作之前和之后各检查一次。一旦滤镜添加完成,你就可以设置 photo record 的状态了。
牛逼!现在你已经拥有执行后台任务的所有必备工具了,是时候回到 View Controller 中修改你的旧代码了。
回到 ListViewController.swift 文件,删掉 lazy var photos 声明,添加下面的声明:
如此你将有一个照片对象的数组和一个等待任务的队列。
下面我们添加一个新的方法用于下载图片信息的 plist 文件。
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {response,data,error in
if data != nil {
let datasourceDictionary = NSPropertyListSerialization.propertyListWithData(data, options: Int(NSPropertyListMutabilityOptions.Immutable.rawValue), format: nil, error: nil) as! NSDictionary
for(key : AnyObject,value : AnyObject) in datasourceDictionary {
let name = key as? String
let url = NSURL(string:value as? String ?? "")
if name != nil && url != nil {
let photoRecord = PhotoRecord(name:name!, url:url!)
self.photos.append(photoRecord)
}
}
self.tableView.reloadData()
}
if error != nil {
let alert = UIAlertView(title:"Oops!",message:error.localizedDescription, delegate:nil, cancelButtonTitle:"OK")
alert.show()
}
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
}
[/sourcecode]
这个方法创建了一个异步的网络请求,请求结束后在主线程回调。文件下载后会被解析成一个 NSDictionary 对象,然后再解出来一个 PhotoRecord 数组。这里你不会直接使用到 NSOperation,而是用到主队列 NSOperationQueue.mainQueue()。
在 ViewDidLoad 方法中调用这个下载函数。
接下来,找到 tableView(_:cellForRowAtIndexPath:) 然后替换成下面的实现:
//1
if cell.accessoryView == nil {
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
cell.accessoryView = indicator
}
let indicator = cell.accessoryView as! UIActivityIndicatorView
//2
let photoDetails = photos[indexPath.row]
//3
cell.textLabel?.text = photoDetails.name
cell.imageView?.image = photoDetails.image
//4
switch (photoDetails.state){
case .Filtered:
indicator.stopAnimating()
case .Failed:
indicator.stopAnimating()
cell.textLabel?.text = "Failed to load"
case .New, .Downloaded:
indicator.startAnimating()
self.startOperationsForPhotoRecord(photoDetails,indexPath:indexPath)
}
return cell
}
[/sourcecode]
请花点时间通读一下下面的注释详解:
现在你可以把 ViewController 里面的 applySepiaFilter 删掉了,添加以下代码,用于启动一个 Operation:
这里,你将把一个 PhotoRecord 和 IndexPath 作为参数传入,基于图片的状态,你可以选择启动下载或者滤镜 Operation。
注意:用来下载和添加滤镜的方法是分开实现的,有可能有些图片已经下载完了,然后被滚出屏幕外了,这时候图片滤镜还没加上。所以下一次用户滚动到同一行的时候,你不需要重新下载图片,只要加上滤镜就行了!牛逼烘烘!:]
现在你要实现上面调用到的方法了。还记住你创建了一个自定义的类PendingOperations 用来跟踪 operation吗?现在你可以用上这个类了!添加下面的代码:
//2
let downloader = ImageDownloader(photoRecord: photoDetails)
//3
downloader.completionBlock = {
if downloader.cancelled {
return
}
dispatch_async(dispatch_get_main_queue(), {
self.pendingOperations.downloadsInProgress.removeValueForKey(indexPath)
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
})
}
//4
pendingOperations.downloadsInProgress[indexPath] = downloader
//5
pendingOperations.downloadQueue.addOperation(downloader)
}
func startFiltrationForRecord(photoDetails: PhotoRecord, indexPath: NSIndexPath){
if let filterOperation = pendingOperations.filtrationsInProgress[indexPath]{
return
}
let filterer = ImageFiltration(photoRecord: photoDetails)
filterer.completionBlock = {
if filterer.cancelled {
return
}
dispatch_async(dispatch_get_main_queue(), {
self.pendingOperations.filtrationsInProgress.removeValueForKey(indexPath)
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
})
}
pendingOperations.filtrationsInProgress[indexPath] = filterer
pendingOperations.filtrationQueue.addOperation(filterer)
}
[/sourcecode]
Okay! 下面这个列表会告诉你这段代码干了些啥:
给图片添加滤镜的操作也是一样的模式,除了使用 ImageFiltration 和 filtrationsInProgress 来追踪任务之外。作为练习,你可以自己尝试重构这部分代码,提取重用部分 :]
最后,你成功了!现在你的工程已经完整了。编译运行一下看看!现在滚动列表将不再卡顿,App 在看得见图片的时候才开始下载和添加滤镜,体验流畅无比!

这难道不是很酷吗?你可以看到小小的努力可以让你的应用变得更加流畅——用户将获得更多乐趣!
能看到这里已经很不容易了!你已经让这个项目优化了许多。但是,我们还是有一些细节可以进行调整。你想要的是变成一个伟大的程序员,而不只是一个好程序员。( You want to be a great programmer, not just a good one!)
也可能已经注意到当你滚动列表把图片滚出屏幕外的时候,那些任务还在不停地下载和添加滤镜。如果你滚得很快,队列将被塞满,滚到底部的时候那些图片要等很久才能出现。理想情况下,我们应该取消那些不在屏幕里的任务。
你不是已经添加了“取消”的代码了吗?现在是时候用上他们了!:]
回到 Xcode,打开 ListViewController.swift。找到 tableView(_:cellForRowAtIndexPath:) 的实现,给 startOperationsForPhotoRecord 的调用包上一个条件判断:
这里你让 Table View 只在不滚动的时候才开始下载。这两个属性其实是 UIScrollView 的属性,UITableView 是 UIScrollView 的子类所以可以直接用。
接下来,要实现 UIScrollView 的 Delegate 方法:
override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
// 2
if !decelerate {
loadImagesForOnscreenCells()
resumeAllOperations()
}
}
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
// 3
loadImagesForOnscreenCells()
resumeAllOperations()
}
[/sourcecode]
这段代码做了这么件事:
现在,我们把漏掉的实现加回 ListViewController.swift 文件中:
func resumeAllOperations () {
pendingOperations.downloadQueue.suspended = false
pendingOperations.filtrationQueue.suspended = false
}
func loadImagesForOnscreenCells () {
//1
if let pathsArray = tableView.indexPathsForVisibleRows() {
//2
var allPendingOperations = Set(pendingOperations.downloadsInProgress.keys.array)
allPendingOperations.unionInPlace(pendingOperations.filtrationsInProgress.keys.array)
//3
var toBeCancelled = allPendingOperations
let visiblePaths = Set(pathsArray as! [NSIndexPath])
toBeCancelled.subtractInPlace(visiblePaths)
//4
var toBeStarted = visiblePaths
toBeStarted.subtractInPlace(allPendingOperations)
// 5
for indexPath in toBeCancelled {
if let pendingDownload = pendingOperations.downloadsInProgress[indexPath] {
pendingDownload.cancel()
}
pendingOperations.downloadsInProgress.removeValueForKey(indexPath)
if let pendingFiltration = pendingOperations.filtrationsInProgress[indexPath] {
pendingFiltration.cancel()
}
pendingOperations.filtrationsInProgress.removeValueForKey(indexPath)
}
// 6
for indexPath in toBeStarted {
let indexPath = indexPath as NSIndexPath
let recordToProcess = self.photos[indexPath.row]
startOperationsForPhotoRecord(recordToProcess, indexPath: indexPath)
}
}
}
[/sourcecode]
suspendAllOperations 和 resumeAllOperations 的实现都很直观了。NSOperationQueues 是可以被挂起的,设置 suspended 为 true 就行了。这样整个队列里所有的任务都会被挂起——你没有办法只挂起单个任务。
loadImagesForOnscreenCells 稍微复杂一点:
编译运行一下,现在你应该有一个更加流畅,资源管理更加合理的应用了!你们的掌声在哪里!

注意到现在只要你停止滚动 Table View,当前屏幕上的 Cell 就会立刻开始下载了。
这里有一个完整的项目工程可供大家下载。
如果你已经完成了这个项目而且确实花时间理解了所有的东西,那么恭喜你!相比你刚开始看这篇文章,你已经是一个更有价值的 iOS 开发者了!多数开发团队都会为拥有一个或两个真正懂得这些东西的开发者而感到幸运。
但是要注意——就像多层嵌套的 block 一样,无理由地滥用多线程也会让你的代码变得难以维护。多线程可能会引入很多难以察觉的bug,只在网络差的时候,设备性能特别好的时候,或者跟你写代码的机器的 CPU 数不一样的时候才会出现。你必须很小心地测试这些代码,经常使用 Instruments(或者你自己喜欢的工具)来确认引入多线程确实让性能得到了提高。
这篇文章里没有提到,Operation 还有一个很有用的特性,就是依赖(dependency)。你可以创建一个依赖于其他 Operation 的 Operation。这个 Operation 只有在那个依赖的 Operation 全部执行完了它才会启动。举个例子:
filterOperation.addDependency(downloadOperation)
[/sourcecode]
要解除依赖关系只要一句代码:
如果用上依赖关系,是否可以简化本文介绍的这个工程呢?你可以用上这个新技能自己试一下 :] 值得注意的是,有依赖关系的 Operation 即使被依赖的 Operation 被取消了,它也依然会被启动,你需要随时牢记这一点。
2022-08-20 原《每周读书》系列更名为《枫影夜读》

还在念书时曾在学校的书店里多次见过《东方快车谋杀案》的封皮,却一直记不住作者的名字。这周末因缘际会,竟一口气读了她三部小说,心中颇感敬佩。
提到英国的侦探小说就不得不提柯南道尔,笔下的福尔摩斯比作家有名的人物,阿加莎克里斯蒂便是与他齐名的侦探小说家,笔下也有波罗侦探与马普尔小姐这样的系列人物。兴许与她创作的时间在 1920——1976 这段时间有关,枫影对这位“侦探小说女王”并不十分熟悉,然而读完《悬崖山庄奇案》,已被其精妙的情节构思所吸引。阿加莎是一位高产的作家,创作生涯几乎每年都有一到两部作品出版,留下的小说作品也有百余部之多。于是枫影又读了同属“波罗侦探系列“”的代表作:《罗杰疑案》与《东方快车谋杀案》。
这三部作品都不算薄,读起来却奇快。阿加莎几乎没用一点高级修饰,人物对话也几乎不描述动作与表情,写作手法更是几乎都一个套路:开场人物——案件发生——推理过程——揭开谜底,但是由于情节设计极为巧妙,小说的结局总能有惊人的反转。至于翻译质量,得益于阿加莎通俗易懂的语言风格,新星出版社出版的这几部作品可读性都极佳,我相信还没读到的其他作品也是一样的。
如果说东野圭吾的推理作品如新世纪福音战士,带有深刻的人性挖掘和阴暗的社会背景,那么阿加莎的作品就是哆啦A梦,有着巧妙的情节编排和明快的抒写笔调。推理小说是强调情节设计的文体,然而东野圭吾的小说却寄予了超出推理本身的深层寓意,比如《白夜行》,是社会的阴暗导致了主角人格扭曲,行事邪恶,唯有心中的爱才是真诚,又比如《嫌疑犯x的献身》,除了推理情节上石神与伽利略的精彩角力之外,更充满了法律与公正的冲突,罪恶与现实的无奈,到头来谁才是真正的残忍,让故事本身超出了侦探小说的属性。
反观阿加莎的作品,她并没有给笔下的故事注入太多沉重的现实,波罗只是个自命不凡矮个子名侦探,他拥有的武器就是他冷静的推理能力,他的凶手都是乖乖呆在那里等着他非凡的推理结束后揭露出来的,没有凶险的抗争也没有血腥的一面(真要有的话波罗应该牺牲很多次了),只靠她精妙的情节设计,让读者拍手叫好。
我想这种语言平易近人,情节扑朔迷离的特色正是其畅销的原因。她喜欢在作品中铺陈所有已知的证据,侦探迷们大可自行推理还原事实真相,再往后读加以验证,而懒人如我则可直接跃进到结局,看大侦探召集所有人宣布推理结果,感受反转结局的魅力。东野的作品由于其附加属性往往较为沉重,有些作品如《嫌疑犯x的献身》可以再看一遍感受内心的震动。而阿加莎的作品则更像如茶余饭后的闲适读物,长途旅行备上一本最好打发时间,一旦解开谜底就不会再看第二遍了。
15.05.31/夜
于自居
2022-08-20 原《每周读书》系列更名为《枫影夜读》

九莉快三十岁的时候在笔记簿上写道:“雨声潺潺,像住在溪边。宁愿天天下雨,以为你是因为下雨不来。”
读完《小团圆》,已分不清盛九莉与张爱玲了,在此之前我对张爱玲知之甚少,只知她是有名的作家,有过不如意的爱情,却万没想到盛九莉即是张爱玲!内心颇为震动。
这位民国的女作家最终在美国逝世,留下的许多作品如《倾城之恋》、《红玫瑰与白玫瑰》等早已家喻户晓,然则《小团圆》却是特别的一部。首先这是一部半自传体小说,女主角就是张爱玲(盛九莉),小说里的张之雍就是她的前夫胡兰成,还有潇洒的母亲与姑姑,都是张爱玲人生中极为重要的人物,读《小团圆》就是读作者曲折的一生。
其次,这部作品在张爱玲辞世 13 年后方得以出版,只因她曾在遗嘱中声明:
(《小团圆》小说要销毁。)这些我没细想,过天再说了。
所以此书的出版曾有微议,然则其中原委宋以朗所写的《前言》已有详解,此处不再赘述。只是这段曲折又让本书添了些许神秘。
且说回《小团圆》,文首的引文在书中首尾各出现了一次,正巧不久前看了新海诚的《言叶之庭》,也是同雨相关的爱情故事:男女主人公以雨为借口,相约在雨亭。“若明日下雨,我便会来。”他们盼雨,九莉也盼,却只盼的一个借口,一声慰藉。
多么苍凉。
小说四处充溢着这种张爱玲式的苍凉。读前两章时总觉得有些过于平淡,直到张之雍的出现,才使故事世界有了波澜。然而轻描淡写正是她的风格,常常不经意间就抛出一句嘲讽,仿佛嘴角一丝冷笑:
自己生活贫乏的人才喜欢刺探别人的私事。
张爱玲的这种风格常使人迷失,这种迷失要归功于一笔带过的转场和突如其来的情感。
比如时空的转场,常常上一句话里人们还坐在厅室吃茶聊天,下一句话就不知过了多少时候,换了个什么地方,只人物还是那些人物,谈论的或许已是别的什么。
又比如人物的出场,在《小团圆》里,仿佛无论何时何地都可以冒出来一个人名,说了一句什么话,连脸面都不大清楚,就已悄然退场。甚至同一个人物在邻近的几句话里就被换了好几个称呼(比如二婶——母亲——蕊秋),你得回过头去想一想,才恍然大悟:噢,原来是她。
但是这种节约的写法却让频繁的转场之间无缝对接,仿佛一镜到底,也是神来之笔。
至于突如其来的情感,有时也令人摸不着头脑。明明盛九莉并没有表露出她深爱张之雍的迹象,却突然一个眼神,内心就澎湃了起来:
她崇拜他,为什么不能让他知道?
这大约也正是张爱玲小说吸引人的地方,就像个谜一样的少女,你自以为借着作者的视角看透了她的内心,却原来什么也没看懂。你以为她冰冷冷不想理睬,回过头来却一个香吻。多么千转百转,多么折磨人心!
二者结合让张爱玲的文笔有如涓涓细流,絮絮叨叨,似耳语,似檐雨,叮叮咚咚,淅淅沥沥,似乎轻飘飘,软绵绵,却不知在何时,早已渗入你的内心,一阵感动。这就是张爱玲式的笔触,无孔不入,细而无声。
《小团圆》就这么在雨声潺潺中落幕,如梦似幻,以全知的视角俯视九莉的人生。这里面有九莉学生时代的迷懵,有后来曲折的爱情,有在美国打胎的恐怖,有她母亲的冷暖,有她姑姑的相依。小团圆并不小,“她”是张爱玲一生的写照,是张爱玲最为深知的一切。
2022-08-20 原《每周读书》系列更名为《枫影夜读》

“黑,真他妈的黑。”
2010 年刘慈欣的《三体3》出版,在推特上曾引发过一阵热潮,当时我很好奇大家都在讨论的“三体”到底是什么,于是便看了《三体》第一部,那时候,《每周读书》刚写到第六篇。
一晃眼 5 年过去了,终于把三部曲全部看完。放下书本,蓝色星球在广袤无垠的黑暗空间中悬浮的影像却久久不能消散,以极高智慧生物的上帝视角回望银河系,回望整个宇宙的场景每每不能忘却。在地铁上捧着张爱玲的《小团圆》却读不下去,思绪竟无法重返地球。
三体中的舞台大,真他妈的大,三体中的世界黑,真他妈的黑。作为一部太空史诗,《三体》的世界构筑在宇宙文明的生存竞争之上,作家把这个基本定律总结为两点:
讨论这两点在现实中是否成立是没有意义的,就像讨论阿西莫夫的机器人三大定律是否成立一样。如果读者并不接受这种前设,那么作品对于读者已兴味全无,而一旦接受这种前设,作家构筑的世界就是一个逻辑自洽的世界,在这个世界之上,你尽可天马行空,自由徜徉。
提到《三体》,读者印象最深刻的大概是作品的“宏大”,这种“大”体现在时间与空间的宇宙尺度上。除开第三部结尾时敷衍式地几句话写完几亿年的时间,单论情节集中的部分,时间跨度也在几百年上下,空间跨度则在太阳系到三体的半人马星系左右,是远超出普通人类一生的时间,是难以想象的太空的广度。于是作品带来的震撼也是成倍的,但这种大跨度也容易给读者带来困惑。
所以作家选择了以公元纪年的人物作为主角,并且到第二部故事发展开始加速时,给予了人物“穿越时间”的能力——冬眠。第二部的主角罗辑就利用冬眠直接跃进到与三体人决战的时刻,到了第三部,故事时间加速更快,主角程心频频进入冬眠状态,只在关键情节触发的时候才苏醒。如此一来,主角与读者拥有相近的知识和体验,故事中“未来”的技术以读者的角度进行解释就自然而然,甚至无关紧要的部分可以用主角的视角直接略过。这点在第三部体现尤其多:尽管时间都在“未来”,但大部分出场人物都是公元人,似乎“未来人”仅仅是作为“群体演员”而存在。
这种人物刻画不足也是《三体》为人诟病之处,毕竟《三体》的“硬科幻”部分精雕细琢无可挑剔,大情节上跌宕起伏,虽是俗套的文明生存抗争,却屡屡出人意料,所以只有人物部分是最好下手开骂的了。这就好像普通人没接触过代码与产品设计,想要批评一个产品做得不好,往往只能动用“怎么也懂一点”的“审美能力”来指栽“配色难看”云云了。
不过《三体》中的人物刻画确实差强人意,尤其是主要女性的角色,苍白无力毫无血色。比如第二部中罗辑的梦中情人庄颜,作者极力想要打造一个小龙女式的超凡脱俗的完美女性,却只给出了一个干巴巴极不自然的提线木偶,与金庸的小龙女相去甚远,最终这位女性角色也是草草收尾,一笔带过。相比之下,第三部的主角程心,虽然被大批读者围攻,形象也还是那么单薄比旁白好不了多少,但至少这位女主角能够给读者留下“恨”的印象,已算不错的成就。不过我想,《三体》中构筑的宇宙已经这么黑,这些光明的女性角色再白纸也是必须的平衡。
这个黑暗的宇宙中,有无法想象的重复着空旷的四维空间,有展开起来无穷无尽的二维平面,有无数个“神”一样的智慧文明,然而根据《三体》的基本设定,这个世界只能是绝望的——宇宙就是一片黑暗森林,走在森林中的人们手中拿着枪,一旦发现目标,不管是老人小孩还是老虎猛兽,统统一枪毙命。《三体》故事越往后就越绝望,太阳系终于消亡在二维空间之中,作者再不吝惜时间,故事发展加速加速再加速,短短几句话之间穿越几百亿年。我想大约作者也绝望了,再怎么挣扎下去,结局都是一样的,宇宙终于会在黑暗森林之中死去,是绝对的死去。
《三体》无疑是一部浪漫主义作品,它如同一部精心策划的大片,用尽一切人类能够达到的技术水平雕琢画面,再普通的战争题材也好,一旦把故事搬到时空超乎想象的太空之中,带来的震撼都是加倍的,然而作者的悲观主义也加倍了。我不去想这种黑暗森林的设定是否符合现实,但假定我是面对黑暗森林的地球人,我大概会同那些“群众演员”一样一时狂欢一时悲恸,面对无法回头的星际远航,我也会同飞船上的军人一样决绝地消灭自己的战友,这就是黑暗森林的悲哀,站在这个角度上,我觉得故事的主角们已经是“神”了,他们代表的是人类的道德律,是人类独有的“爱”,若失了这些近乎顽固的坚持,人类将不再是人类。
然而我们毕竟不是主角。
黑,真他妈的黑。
15.05.23/凌晨
于自宅
我读的是 z.cn 的 Kindle 版《三体全集》
2022-08-20 原《每周读书》系列更名为《枫影夜读》

三岛由纪夫的同性恋倾向是他神秘魅力的一部分,《假面的告白》就是他的成名作。尽管作家至死都没有公开承认过自己的性倾向,并且娶妻生子,但是这部充满细腻的同性心理描写的作品却让人觉得——至少在写作当时——作家与主角是有着相同的心情的。
这种对男性身体的迷恋与欲望,在作家笔下是如此细腻而费解,令人不由眉头紧蹙。然而皱着眉头把这部作品看完,从头做读书笔记的时候,却发现这部作品出奇的美丽。
我个人很喜欢阅读写得漂亮的文字,具体地说,是像诗一般的优雅的文字。三岛的文字就有着诗一般的优雅。这种写法有个好处,就是可以轻易做到隐晦而不突兀。但与此同时流畅自如就成了一个挑战。能放不能收是很多现代诗歌容易犯的毛病,在小说里使用诗意的写法,往往会因此让作品变得晦涩,幸好三岛不会。
三岛的隐晦的写法有其必要性,其一是体现在对抽象事物的具象表达上。三岛长于人物内心世界的细致刻画,多用意味深长的镜头来演绎人物的思考,也常用优雅的比拟,把不可捉摸的思维投影成美丽的画面,色彩斑斓,明暗有度。诗性是三岛华丽的武器。
另一个必要则是作家对不能露骨表达的事物采用的委婉的手法。三岛多写禁忌题材,性倒错,性描写,以恶为美,反传统,反道德,这些话题似乎总能见诸三岛笔下。这让我想起欧洲的绘画艺术的历史,在反前人理念的基础上,艺术家们不停地翻涌推动新的艺术的诞生,从带有实用目的的装饰壁画到文艺复兴,再到古典主义,现代主义,自然主义,新古典主义,后现代主义……艺术家们力图挣脱“没什么可画”的无奈,而最佳的武器就是否定。仔细想想,音乐、物理、文学……人类的知识岂不都是如此。人类就是在否定前人的经验中不断地进步啊!
《假面的告白》完成于 1949 年,这部作品在保守年代引发轩然大波,即便是今天,同性也还远没有到被社会舒服地接受的地步,小说的大胆与突破在当时可想而知。
这部被称为“半自传体”小说的作品,与三岛的人生经历有许多相似之处,小说第一章所描述的幼年时期基本就是以三岛自身为原型:出生在一个没落的贵族家庭,自小被家中掌握大权的祖母强行抱养,在过度的保护中成长,身体孱弱,性格阴柔,也因此产生“性倒错”而深感苦恼。
由此苦恼展开了小说最令人头疼的第二章,着重描写对男同学的迷恋,以及主角对性倒错的认识,多用幻想写法,深沉难解。然而第三章开始主角竟然试图去爱一位女子——园子,这表明主角试图改变自己的“不正常性”,去适应世人的“正常”。甚至发出:“人世间是否有纯粹的精神的爱恋?”的疑问,然而从主角的试验结果来看,答案是否定的。
如果第三章是主角在精神上企图去爱女人的探索,那么第四章就是生理上企图对女性产生欲望的尝试。他甚至决心去招妓,在失败之后,主角终于确信了自己的“不正常性”是不可能改变了。后来遇上了已为人妻的园子,他们频频见面,却只是聊天。最后在园子的“你是否已经……”的诘问中沉默告终。
书名是《假面的告白》,我以为主角会在最后摘下假面,然而不,主角一直活在自己的演戏里,并且“发誓对导演忠诚”。
看完这本小说,再回想《金阁寺》,有些想不通的地方就豁然开朗了。设若金阁寺所代表的美就是人世间通常的“男女之恋”的美,而沟口却屡屡和女人在关键时刻就浮现金阁寺的幻影而失败,那么金阁就是假面向往而不可得的女性了。金阁寺中的沟口或许没有同性的倾向,但是他渴望金阁,憎恶金阁的双重心理却与假面向往女性却又屡屡失败的心情是一致的。最后沟口决定烧掉金阁,可以说就是假面试图接触女性,回归“正常”的努力。
最后沟口终于烧掉了金阁,坐在草地上吐出烟圈叹了一句:“我要,活下去”。这大约就是假面屡试屡败,却始终没有摘下面具,向生活妥协的无奈。可以说作家在同性这件事情上获得了无穷的源泉,他巧妙地把这些心理以另一种形式替换了展现出来,但根源其实一致的。
1949 年《假面的告白》发表。
1956 年《金阁寺》发表。
1958 年三岛由纪夫与平冈瑶子结为夫妻。
15.05.05/中午
于 T.i.T
本书购于广州 1200 Book Shop,这是一家 24 小时书店,位于天河体育东路,店面不大,藏书亦不算多,胜在 24 小时营业,有按出版社分类的书架,形式颇为新颖。
2022-08-20 原《每周读书》系列更名为《枫影夜读》

从书架上拣一本最薄的三岛由纪夫的小说买下,正好是《纯白之夜》。上海译文出版社出版的这套三岛的合集甚合我心,装帧简约,朴素干净,最赞的是这本小说没有莫名其妙的前言和后记,真是难得。
小说一个晚上就看完了,在三岛一如既往的细腻与优雅中度过,真好。同《金阁寺》那种绚烂的美的重构相比,这部小说要粗浅得多。尽管作家借小说人物发出了性与爱分离的思考,却只是蜻蜓点水,更像是炫示技巧的小品。
故事以战后的日本为背景,围绕一对中产夫妇(恒彦与郁子)展开。在这个平静而“幸福”的家庭里,由于第三者楠的插入引发了一阵波澜。可以说这种故事在今天已是被写烂了的题材,但是作家高明的地方就在于,通过细致入微的人物心理的描写来推动剧情的发展,情节在这部作品里面成为了思想的附庸。全书的笔墨着重在描写郁子复杂多变,渴望与抑制渴望的二律背反的心理波折。作家笔下的人物都是多思而敏感的,每个人物心中隐晦的恶的人性,与各不相同的性格,在作家娴熟的技巧下被一一解构,重塑成鲜明饱满的角色。
作家的技巧在这部作品中展示得淋漓尽致。通感(联觉)与比喻是其最擅长的武器,这种朴素的技巧把敏锐的洞察翻译成通俗的表述,令读者不时有心中一亮,“啊,就是这样”的感觉。比如郁子初次收到楠的情书是,那种期待渴望又试图隐瞒的心情:
如此说来,是因为郁子很久没有变成如此孩子气的好奇心的俘虏了。就像得到点心的孩子一样,想快点回家打开手提包看看的好奇心,眼下正是这一点支配着她,驱使着她热情四溢。
又比如文中对故事转折的暗示:
陷入这种禁欲主义的令人喟叹的孩子,要是他枕边的点心不给老鼠拖走,它是很少会回心转意的。
这些巧妙的比喻胜过直抒百倍,至于通感的运用,则多表现在风景描写与心理波动的穿插上,以一种蒙太奇式的手法,展开一个美绝的镜头,让画面犹如有了背景乐而生动起来:
这期间,脸色苍白的楠夫人盛装丽服的身影总在郁子的脑海里萦绕不去。倒是在黄昏的坡道上往下跑时发出清脆响声的载重马车,打破了这一幻影。
又比如:
仿若不知为何阴沉下来的旷野,鸟儿一掠而过的影子。
作家熟练的文笔,向读者展示了一幅幅美丽的画面,使人物内心的波澜细腻而不空洞,小说就这么在柔美的心理曲折中步步推进。
然而整体来说,这部作品有思考却没有答案,丈夫恒彦作为一个重要的角色,却仿佛被架空了,略显苍白。最后的主角的自杀,虽有过一些前置铺垫,却仍显得仓促而意味不明。所以假使这部作品可谓是不错的闲适读物,挺好的技巧学习之作,但作为严肃的文学作品来看待,则略显浅薄了。15.04.28/下午
于 T.i.T 创意园
2022-08-20 原《每周读书》系列更名为《枫影夜读》

决绝地合上诗集的瞬间,薄暮的霞光正好漫上鞋底。读余秀华的诗,你找不到何其芳的画梦的技巧,也找不到徐志摩的翡冷翠的高雅。但是有什么所谓呢?
已是十分难得的干净与诚挚了。
刘年的后记无疑是这部诗集最大的败笔,充满了文人的自以为是的酸气和莫名其妙的傲气。然而我却十分赞同这个观点:诗歌作为一种小众的文体,在今天已不仅仅是衰落,诗歌已经沦为戏谑与嘲弄的对象,甚至我自己也不敢承认我书写着诗歌,一如我不敢承认我的政治身份。这是怎样一种病态啊!
余诗抚去了《诗歌报》一类排资论辈自欺欺人的酸腐,唯有真挚充盈的情感保留了下来,悲伤却不绝望,苦痛然而敞亮。我想这种无以言尽的明亮之色正是余诗最为动人的地方。
然而除却真情,余的技巧仍有需要打磨的地方,没有何其芳绵绵不绝行云流水的华辞丽句,也没有戴望舒层层叠叠抑扬顿挫的音律起伏,更受限于诗人生活的方寸之地,余诗的意象来去不过星月黄昏与村野农作,与大家的丰富多彩相比,要苍白得多。
所以读余秀华的诗,常令你有无法尽兴之感,但是余的苦难的人生与其堂堂皇皇的诗句却总让你有一种不舍。尽管我觉得过分谈及余的残疾与不幸其实是对诗人的不公平,余固然因为不幸而愈美,却并不因为不幸而存在,余的诗句不需要廉价的同情。
余诗的光明是我们这些忙碌与大都市的蝼蚁所缺失的,这种丰满而纯净的情感,是我们不停下脚步就会轻易忽略的风景。读诗需要一方宁静,如同你早已干涸的内心的荒原,突然红了一叶舞动的花。在你诧异的眼帘上扬的瞬间,一瓣嫣红早已拥抱另一瓣,在一个有阳光的夏天的午后,轻轻点碎一方平静的湖面,荡出的波浪再无法收敛。
我不信你不曾这样,颤抖过。
15.04.22/凌晨 于自居

还在上学的时候,对于人生至俗的问题:
你的梦想是什么?
我是这么回答的:
当一名作家。
天真如幼稚园小朋友连科学家是什么都不知道一样,“作家”一词于我,就如同在黑暗的柔波中徜徉的闪烁的星斑,耀眼而无法触及。后来我说:“作家养不活自己。”
如今我坐在这个浮躁的大都市里,在这个不是 1 就是 0 的世界里养活我自己。在这个没有梦想的时代,如果你再问我:“你的梦想是什么?”没有梦想的我大概也只剩下这么一个尘封的答案了吧:我想当一名作家。
很开心这几年还有“每周读书”,它大约是我与这个梦想的世界的唯一纤细的联系了。每隔 8 期我会整理一份书单,以下是 65-72 期的书单:
2022-08-20 原《每周读书》系列更名为《枫影夜读》

有人问:
为什么精神病人都是艺术家?
我想并非精神病人是艺术家,只是二者有共通之处罢了。这个世界所有的事物都在对外广播全频段的信息,普通人为了防止信息过载,忽略了大部分小众的频段,只保留了主流的信息,这被称为“正常”。而精神病人与艺术家的共通之处在于:他们都能接收小众频段的信息。只是艺术家除了小众频段之外还能处理主流频段,而精神病人只接受到小众频段罢了。
在《金阁寺》这部小说里,每个主要角色都有自己独特的世界观,他们发出的小众频段的信息被作者以主流的信号转译出来,这大约便是小说家的本事吧。这部作品是根据 1950 年纵火焚烧金阁寺的真实事件改编的。说是改编,但其实除了放火这点,其他部分都是虚构多于现实。
主角沟口从小由于结巴的关系,有着极自卑的内心。“世人总以为要借助镜子才能看到自己,残疾人却被迫在鼻尖挂着一块镜子,时时看到丑陋的自己”。沟口的这种自卑又与他自小从父亲口中听到的美丽的金阁寺相生相伴,这种想象中的金阁的极美,是脱离了现实,只依存于沟口心中的美。
沟口的父亲病重之际,带着沟口到金阁寺托孤,不久后终于病逝。沟口第一次看到现实中的金阁寺,其实没有想象中那么美。在这里他遇到了少年鹤川,这个纯洁的透明的结构体,总是能把自己的意思误解成光明的意思。鹤川就是沟口的正片,是沟口与这个世界的光明的唯一联系。
《金阁寺》里描绘的世界是极丑恶的,但却又如此真实。沟口憎恨母亲,因他曾在暑假的某个晚上撞到母亲与另一个亲戚的苟且之事。沟口也不喜欢父亲,这个懦弱的寒碜的和尚在那天晚上用大手掌捂住了沟口的眼睛,也不知到底是出于慈祥,还是怯懦。而金阁寺的住持又分明是个嗜财好色的丑陋的和尚,再到后来遇上的大学同学柏木,简直就是恶魔的化身。
柏木是个有 X 型腿的残疾人。他失去童贞的故事丑恶得令人震撼。由于丑陋的 X 腿的残疾,柏木有着与沟口类似的心情。如果说鹤川是以极纯洁来应对世界,那么柏木就是以极丑恶来否定世界。沟口在与鹤川、柏木交往的过程中,大概还不知道应当如何应对这个残酷的现实。在遇到柏木之后,他也试图接近女子,但是每次在即将与女子发生关系的时候,金阁的幻影出现了。金阁拒绝了女子,也就是沟口拒绝了女子,他无能了。金阁的美是沟口的向往的极美,同时金阁的美也是沟口的极恨,整部小说充斥着丑恶与美的强烈冲突,这种冲突左右着沟口的人生。
在鹤川死后,沟口心中的光明的世界开始崩塌,天平终于倾向丑恶黑暗的一边。最后沟口把金阁寺烧了。
就如前文所述,这个世界所有的事物都在对外做全频段广播,小说亦如是。尽管作者已经把大部分的信息用主流的频段书写出来,但是还是有很多小众的信息需要读者自己调整频道去收听。只有当你的接收频段与作品和谐的时候,才能体会到作品的共鸣。
有些作品被评为“普通”大约也是这个原因:它的所有的信息都被主流频段包括了,除此之外别无他物,也就是所谓的“肤浅”。
我想作者在创作这部作品的时候已经把自己与角色融为一起,分不开了。现实中的三岛是个潇洒的公子,但却因为自己的孱弱的身体而感到自卑。在环游欧洲结束之后他开始创作这部作品,对于美的感受大约与他在希腊的旅行不无关系。
世人总喜欢自以为是地刻意否定外在的美,以为这种虚伪的评价可以换取多一分高尚,实在太廉价。三岛在这部作品中,用流畅的文笔把景物的、人物的外在的美描绘得淋漓尽致,这种优雅成为了这部小说的信息通道,而通过这种通道流泻出来的,却是令读者皱眉的沉重的哲思。
鹤川的透明与脆弱的心底隐藏了深沉的苦痛,柏木的孤僻与阴暗的表面暗含了否定世界的丑恶。沟口作为故事的主角,则多变而心酸。他在火烧金阁寺的那个夜晚,终于明白改变自己认识的世界并不需要毁灭,只需要改变自己的认识,而改变认识其实并不依靠这种无效的行动,但他终于还是烧了。
与现实的纵火事件不同,作者并没有让沟口在纵火后用匕首剖腹,相反地,沟口在冲上金阁寺顶的时候因为敲不开门,终于冲出烈火,躺倒在星空之中。坐在黑暗的夜里的沟口,点燃一支香烟,静静地望着远处熊熊的火焰,发出一声沉重的叹息:
我要活下去!
知道三岛还是因为川端康成。三岛是兵变失败后切腹自杀的,自杀后只有亦师亦友的川端康成被获准进入,随后不久川端康成也自杀了。由于对三岛本人了解甚少,我并不清楚他一定要切腹的真实原因,但是通过《金阁寺》所描绘的世界,我们能够知道故事里的人物所接收的信息太多,每一个人物都是一个世界。世界在人物的认识里,人物活在自己的世界里,如果有什么原因一定要离开这个世界,我想大约是这个我所认识的世界太丑陋,而我对此无能为力,甚至根本无法改变我的认识,这时候离开就是一种解脱。
就如小说里多次提及的《临济录》里的句子:
逢佛杀佛,逢祖杀祖,
逢罗汉杀罗汉,逢父母杀父母,
逢家眷杀家眷,
始得解脱。
15.04.18/下午
于沙园 Costa Coffee